mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-07 08:39:00 +00:00
Merge branch 'master' into primitive_restart
Conflicts: Source/Core/VideoCommon/Src/VideoConfig.h Source/Plugins/Plugin_VideoDX9/Src/main.cpp Source/Plugins/Plugin_VideoOGL/Src/Render.cpp
This commit is contained in:
commit
702198f39b
334 changed files with 21473 additions and 18765 deletions
|
@ -76,7 +76,7 @@ public:
|
|||
g_wave_writer.SetSkipSilence(false);
|
||||
NOTICE_LOG(DSPHLE, "Starting Audio logging");
|
||||
} else {
|
||||
WARN_LOG(DSPHLE, "Audio logging already started");
|
||||
WARN_LOG(DSPHLE, "Audio logging has already been started");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public:
|
|||
g_wave_writer.Stop();
|
||||
NOTICE_LOG(DSPHLE, "Stopping Audio logging");
|
||||
} else {
|
||||
WARN_LOG(DSPHLE, "Audio logging already stopped");
|
||||
WARN_LOG(DSPHLE, "Audio logging has already been stopped");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ bool WaveFileWriter::Start(const char *filename, unsigned int HLESampleRate)
|
|||
|
||||
// We are now at offset 44
|
||||
if (file.Tell() != 44)
|
||||
PanicAlert("wrong offset: %lld", (long long)file.Tell());
|
||||
PanicAlert("Wrong offset: %lld", (long long)file.Tell());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -66,23 +66,26 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
|
|||
#define Crash() {asm ("int $3");}
|
||||
#endif
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
|
||||
// GCC 4.8 defines all the rotate functions now
|
||||
// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit
|
||||
#ifndef _rotl
|
||||
inline u32 _rotl(u32 x, int shift) {
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
}
|
||||
|
||||
inline u64 _rotl64(u64 x, unsigned int shift){
|
||||
unsigned int n = shift % 64;
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
inline u32 _rotr(u32 x, int shift) {
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
return (x >> shift) | (x << (32 - shift));
|
||||
}
|
||||
#endif
|
||||
|
||||
inline u64 _rotl64(u64 x, unsigned int shift){
|
||||
unsigned int n = shift % 64;
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
inline u64 _rotr64(u64 x, unsigned int shift){
|
||||
unsigned int n = shift % 64;
|
||||
|
|
|
@ -36,15 +36,16 @@ public:
|
|||
return (0 == m_size);
|
||||
}
|
||||
|
||||
const T& Front() const
|
||||
T& Front() const
|
||||
{
|
||||
return *m_read_ptr->current;
|
||||
}
|
||||
|
||||
void Push(const T& t)
|
||||
template <typename Arg>
|
||||
void Push(Arg&& t)
|
||||
{
|
||||
// create the element, add it to the queue
|
||||
m_write_ptr->current = new T(t);
|
||||
m_write_ptr->current = new T(std::forward<Arg>(t));
|
||||
// set the next pointer to a new element ptr
|
||||
// then advance the write pointer
|
||||
m_write_ptr = m_write_ptr->next = new ElementPtr();
|
||||
|
@ -67,7 +68,7 @@ public:
|
|||
if (Empty())
|
||||
return false;
|
||||
|
||||
t = Front();
|
||||
t = std::move(Front());
|
||||
Pop();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -124,7 +124,7 @@ bool Delete(const std::string &filename)
|
|||
// being there, not the actual delete.
|
||||
if (!Exists(filename))
|
||||
{
|
||||
WARN_LOG(COMMON, "Delete: %s does not exists", filename.c_str());
|
||||
WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ bool CreateFullPath(const std::string &fullPath)
|
|||
panicCounter--;
|
||||
if (panicCounter <= 0)
|
||||
{
|
||||
ERROR_LOG(COMMON, "CreateFullPath: directory structure too deep");
|
||||
ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep");
|
||||
return false;
|
||||
}
|
||||
position++;
|
||||
|
@ -324,7 +324,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
|||
goto bail;
|
||||
}
|
||||
}
|
||||
// close flushs
|
||||
// close files
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
return true;
|
||||
|
@ -669,7 +669,7 @@ std::string GetSysDirectory()
|
|||
|
||||
// Returns a string with a Dolphin data dir or file in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
||||
{
|
||||
static std::string paths[NUM_PATH_INDICES];
|
||||
|
||||
|
@ -723,11 +723,11 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
|||
if (!newPath.empty())
|
||||
{
|
||||
if(DirIDX != D_WIIROOT_IDX)
|
||||
PanicAlert("trying to change user path other than wii root");
|
||||
PanicAlert("Trying to change user path other than Wii root");
|
||||
|
||||
if (!File::IsDirectory(newPath))
|
||||
{
|
||||
WARN_LOG(COMMON, "Invalid path specified %s, wii user path will be set to default", newPath.c_str());
|
||||
WARN_LOG(COMMON, "Invalid path specified %s, Wii user path will be set to default", newPath.c_str());
|
||||
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
|
||||
}
|
||||
else
|
||||
|
@ -742,6 +742,19 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
|||
return paths[DirIDX];
|
||||
}
|
||||
|
||||
std::string GetThemeDir(const std::string& theme_name)
|
||||
{
|
||||
std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/";
|
||||
|
||||
#if !defined(_WIN32)
|
||||
// If theme does not exist in user's dir load from shared directory
|
||||
if (!File::Exists(dir))
|
||||
dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
|
||||
#endif
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
bool WriteStringToFile(bool text_file, const std::string &str, const char *filename)
|
||||
{
|
||||
return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
|
||||
|
|
|
@ -132,7 +132,10 @@ bool SetCurrentDir(const std::string &directory);
|
|||
|
||||
// Returns a pointer to a string with a Dolphin data dir in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
|
||||
|
||||
// probably doesn't belong here
|
||||
std::string GetThemeDir(const std::string& theme_name);
|
||||
|
||||
// Returns the path to where the sys file are
|
||||
std::string GetSysDirectory();
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
|
||||
void Log(LogTypes::LOG_LEVELS, const char *msg);
|
||||
|
||||
bool IsValid() { return (m_logfile != NULL); }
|
||||
bool IsValid() { return (bool)m_logfile; }
|
||||
bool IsEnabled() const { return m_enable; }
|
||||
void SetEnable(bool enable) { m_enable = enable; }
|
||||
|
||||
|
|
|
@ -5,9 +5,26 @@
|
|||
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
#ifndef __has_include
|
||||
#define __has_include(s) 0
|
||||
#endif
|
||||
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID
|
||||
|
||||
// GCC 4.4 provides <condition_variable>
|
||||
#include <condition_variable>
|
||||
|
||||
#elif __has_include(<condition_variable>)
|
||||
|
||||
// clang and libc++ provide <condition_variable> on OSX. However, the version
|
||||
// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable.
|
||||
//
|
||||
// We work around this issue by undefining and redefining _.
|
||||
|
||||
#undef _
|
||||
#include <condition_variable>
|
||||
#define _(s) wxGetTranslation((s))
|
||||
|
||||
#else
|
||||
|
||||
// partial std::condition_variable implementation for win32/pthread
|
||||
|
|
|
@ -5,9 +5,16 @@
|
|||
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
#ifndef __has_include
|
||||
#define __has_include(s) 0
|
||||
#endif
|
||||
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID
|
||||
// GCC 4.4 provides <mutex>
|
||||
#include <mutex>
|
||||
#elif __has_include(<mutex>)
|
||||
// Clang + libc++
|
||||
#include <mutex>
|
||||
#else
|
||||
|
||||
// partial <mutex> implementation for win32/pthread
|
||||
|
|
|
@ -5,12 +5,19 @@
|
|||
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
|
||||
#ifndef __has_include
|
||||
#define __has_include(s) 0
|
||||
#endif
|
||||
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID
|
||||
// GCC 4.4 provides <thread>
|
||||
#ifndef _GLIBCXX_USE_SCHED_YIELD
|
||||
#define _GLIBCXX_USE_SCHED_YIELD
|
||||
#endif
|
||||
#include <thread>
|
||||
#elif __has_include(<thread>)
|
||||
// Clang + libc++
|
||||
#include <thread>
|
||||
#else
|
||||
|
||||
// partial std::thread implementation for win32/pthread
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
#ifndef _THREAD_H_
|
||||
#define _THREAD_H_
|
||||
|
||||
#include "StdThread.h"
|
||||
#include "StdMutex.h"
|
||||
#include "StdConditionVariable.h"
|
||||
#include "StdMutex.h"
|
||||
#include "StdThread.h"
|
||||
|
||||
// Don't include common.h here as it will break LogManager
|
||||
#include "CommonTypes.h"
|
||||
|
|
|
@ -69,8 +69,7 @@ set(SRCS Src/ActionReplay.cpp
|
|||
Src/HW/CPU.cpp
|
||||
Src/HW/DSP.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AX.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_CARD.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
|
||||
|
|
|
@ -261,7 +261,6 @@
|
|||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCodes.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AX.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_GBA.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_InitAudioSystem.cpp" />
|
||||
|
@ -465,11 +464,8 @@
|
|||
<ClInclude Include="Src\HW\DSPHLE\MailHandler.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCodes.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_GBA.h" />
|
||||
|
@ -602,4 +598,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -196,9 +196,6 @@
|
|||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
|
@ -738,21 +735,12 @@
|
|||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h">
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -176,7 +176,7 @@ bool CBoot::Load_BS2(const std::string& _rBootROMFilename)
|
|||
|
||||
std::string BootRegion = _rBootROMFilename.substr(_rBootROMFilename.find_last_of(DIR_SEP) - 3, 3);
|
||||
if (BootRegion != ipl_region)
|
||||
PanicAlert("%s ipl found in %s directory, the disc may not be recognized", ipl_region.c_str(), BootRegion.c_str());
|
||||
PanicAlert("%s IPL found in %s directory. The disc may not be recognized", ipl_region.c_str(), BootRegion.c_str());
|
||||
|
||||
// Run the descrambler over the encrypted section containing BS1/BS2
|
||||
CEXIIPL::Descrambler((u8*)data.data()+0x100, 0x1AFE00);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "SysConf.h"
|
||||
|
||||
// DSP Backend Types
|
||||
#define BACKEND_NULLSOUND "No audio output"
|
||||
#define BACKEND_NULLSOUND _trans("No audio output")
|
||||
#define BACKEND_ALSA "ALSA"
|
||||
#define BACKEND_AOSOUND "AOSound"
|
||||
#define BACKEND_COREAUDIO "CoreAudio"
|
||||
|
|
|
@ -38,12 +38,12 @@ void Console_Submit(const char *cmd)
|
|||
CASE1("r")
|
||||
{
|
||||
Core::StartTrace(false);
|
||||
INFO_LOG(CONSOLE, "read tracing started.");
|
||||
INFO_LOG(CONSOLE, "Read tracing started.");
|
||||
}
|
||||
CASE1("w")
|
||||
{
|
||||
Core::StartTrace(true);
|
||||
INFO_LOG(CONSOLE, "write tracing started.");
|
||||
INFO_LOG(CONSOLE, "Write tracing started.");
|
||||
}
|
||||
CASE("trans")
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
|||
bCPUThread(true), bDSPThread(false), bDSPHLE(true),
|
||||
bSkipIdle(true), bNTSC(false), bForceNTSCJ(false),
|
||||
bHLE_BS2(true), bEnableCheats(false),
|
||||
bMergeBlocks(false),
|
||||
bMergeBlocks(false), bEnableMemcardSaving(true),
|
||||
bDPL2Decoder(false), iLatency(14),
|
||||
bRunCompareServer(false), bRunCompareClient(false),
|
||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
|
||||
|
@ -81,6 +81,7 @@ void SCoreStartupParameter::LoadDefaults()
|
|||
bSyncGPU = false;
|
||||
bFastDiscSpeed = false;
|
||||
bMergeBlocks = false;
|
||||
bEnableMemcardSaving = true;
|
||||
SelectedLanguage = 0;
|
||||
bWii = false;
|
||||
bDPL2Decoder = false;
|
||||
|
@ -326,7 +327,7 @@ bool SCoreStartupParameter::AutoSetup(EBootBS2 _BootBS2)
|
|||
{
|
||||
if (!File::Exists(m_strBootROM))
|
||||
{
|
||||
WARN_LOG(BOOT, "bootrom file %s not found - using HLE.", m_strBootROM.c_str());
|
||||
WARN_LOG(BOOT, "Bootrom file %s not found - using HLE.", m_strBootROM.c_str());
|
||||
bHLE_BS2 = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ struct SCoreStartupParameter
|
|||
bool bHLE_BS2;
|
||||
bool bEnableCheats;
|
||||
bool bMergeBlocks;
|
||||
bool bEnableMemcardSaving;
|
||||
|
||||
bool bDPL2Decoder;
|
||||
int iLatency;
|
||||
|
|
|
@ -318,11 +318,11 @@ static void gdsp_do_dma()
|
|||
|
||||
if (len > 0x4000)
|
||||
{
|
||||
ERROR_LOG(DSPLLE, "DMA ERROR pc: %04x ctl: %04x addr: %08x da: %04x size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len);
|
||||
ERROR_LOG(DSPLLE, "DMA ERROR: PC: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len);
|
||||
exit(0);
|
||||
}
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
DEBUG_LOG(DSPLLE, "DMA pc: %04x ctl: %04x addr: %08x da: %04x size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len);
|
||||
DEBUG_LOG(DSPLLE, "DMA pc: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len);
|
||||
#endif
|
||||
switch (ctl & 0x3)
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ u16 dsp_dmem_read(u16 addr)
|
|||
return g_dsp.dram[addr & DSP_DRAM_MASK];
|
||||
|
||||
case 0x1: // 1xxx COEF
|
||||
DEBUG_LOG(DSPLLE, "%04x : Coef Read @ %04x", g_dsp.pc, addr);
|
||||
DEBUG_LOG(DSPLLE, "%04x : Coefficient Read @ %04x", g_dsp.pc, addr);
|
||||
return g_dsp.coef[addr & DSP_COEF_MASK];
|
||||
|
||||
case 0xf: // Fxxx HW regs
|
||||
|
|
|
@ -191,7 +191,7 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
|||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(AUDIO_INTERFACE, "unknown read 0x%08x", _Address);
|
||||
ERROR_LOG(AUDIO_INTERFACE, "Unknown read 0x%08x", _Address);
|
||||
_dbg_assert_msg_(AUDIO_INTERFACE, 0, "AudioInterface - Read from 0x%08x", _Address);
|
||||
_rReturnValue = 0;
|
||||
return;
|
||||
|
@ -212,13 +212,13 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
|
||||
// Set frequency of streaming audio
|
||||
if (tmpAICtrl.AISFR != m_Control.AISFR)
|
||||
{
|
||||
{
|
||||
DEBUG_LOG(AUDIO_INTERFACE, "Change AISFR to %s", tmpAICtrl.AISFR ? "48khz":"32khz");
|
||||
m_Control.AISFR = tmpAICtrl.AISFR;
|
||||
}
|
||||
// Set frequency of DMA
|
||||
if (tmpAICtrl.AIDFR != m_Control.AIDFR)
|
||||
{
|
||||
{
|
||||
DEBUG_LOG(AUDIO_INTERFACE, "Change AIDFR to %s", tmpAICtrl.AIDFR ? "32khz":"48khz");
|
||||
m_Control.AIDFR = tmpAICtrl.AIDFR;
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(AUDIO_INTERFACE, "unknown write %08x @ %08x", _Value, _Address);
|
||||
ERROR_LOG(AUDIO_INTERFACE, "Unknown write %08x @ %08x", _Value, _Address);
|
||||
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AIS - Write %08x to %08x", _Value, _Address);
|
||||
break;
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ static void UpdateInterrupts()
|
|||
}
|
||||
|
||||
static void GenerateAudioInterrupt()
|
||||
{
|
||||
{
|
||||
m_Control.AIINT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampl
|
|||
unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate)
|
||||
{
|
||||
if (m_Control.PSTAT && !CCPU::IsStepping())
|
||||
{
|
||||
{
|
||||
static int pos = 0;
|
||||
static short pcm[NGCADPCM::SAMPLES_PER_BLOCK*2];
|
||||
const int lvolume = m_Volume.left;
|
||||
|
@ -443,7 +443,7 @@ static void IncreaseSampleCount(const u32 _iAmount)
|
|||
{
|
||||
m_SampleCounter += _iAmount;
|
||||
if (m_Control.AIINTVLD && (m_SampleCounter >= m_InterruptTiming))
|
||||
{
|
||||
{
|
||||
GenerateAudioInterrupt();
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ void Update(u64 userdata, int cyclesLate)
|
|||
{
|
||||
const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime;
|
||||
if (Diff > g_CPUCyclesPerSample)
|
||||
{
|
||||
{
|
||||
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
|
||||
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
|
||||
IncreaseSampleCount(Samples);
|
||||
|
|
|
@ -334,7 +334,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
|
|||
|
||||
// ARAM
|
||||
case AR_INFO:
|
||||
//PanicAlert("read %x %x", g_ARAM_Info.Hex,PowerPC::ppcState.pc);
|
||||
//PanicAlert("Read %x %x", g_ARAM_Info.Hex,PowerPC::ppcState.pc);
|
||||
_uReturnValue = g_ARAM_Info.Hex;
|
||||
break;
|
||||
|
||||
|
@ -647,6 +647,7 @@ void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, bool _bSet)
|
|||
{
|
||||
CoreTiming::ScheduleEvent_Threadsafe(
|
||||
0, et_GenerateDSPInterrupt, type | (_bSet<<16));
|
||||
CoreTiming::ForceExceptionCheck(100);
|
||||
}
|
||||
|
||||
// called whenever SystemTimers thinks the dsp deserves a few more cycles
|
||||
|
@ -696,8 +697,8 @@ void Do_ARAM_DMA()
|
|||
g_dspState.DSPControl.DMAState = 1;
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
|
||||
|
||||
// Force an early exception check. Fixes RE2 audio.
|
||||
if (g_arDMA.Cnt.count == 4096)
|
||||
// Force an early exception check on large transfers. Fixes RE2 audio.
|
||||
if (g_arDMA.Cnt.count > 2048 && g_arDMA.Cnt.count <= 10240)
|
||||
CoreTiming::ForceExceptionCheck(100);
|
||||
|
||||
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
|
||||
|
|
|
@ -273,7 +273,7 @@ u16 DSPHLE::DSP_WriteControlRegister(unsigned short _Value)
|
|||
UDSPControl Temp(_Value);
|
||||
if (!m_InitMixer)
|
||||
{
|
||||
if (!Temp.DSPHalt && Temp.DSPInit)
|
||||
if (!Temp.DSPHalt)
|
||||
{
|
||||
InitMixer();
|
||||
}
|
||||
|
|
|
@ -17,29 +17,78 @@
|
|||
|
||||
#include "UCode_AX.h"
|
||||
#include "../../DSP.h"
|
||||
#include "FileUtil.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
#define AX_GC
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc)
|
||||
: IUCode(dsp_hle, crc)
|
||||
, m_work_available(false)
|
||||
, m_cmdlist_size(0)
|
||||
, m_axthread(&SpawnAXThread, this)
|
||||
, m_run_on_thread(SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread)
|
||||
{
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_AX: crc=%08x", crc);
|
||||
m_rMailHandler.PushMail(DSP_INIT);
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
|
||||
LoadResamplingCoefficients();
|
||||
|
||||
if (m_run_on_thread)
|
||||
m_axthread = std::thread(SpawnAXThread, this);
|
||||
}
|
||||
|
||||
CUCode_AX::~CUCode_AX()
|
||||
{
|
||||
m_cmdlist_size = (u16)-1; // Special value to signal end
|
||||
NotifyAXThread();
|
||||
m_axthread.join();
|
||||
if (m_run_on_thread)
|
||||
{
|
||||
m_cmdlist_size = (u16)-1; // Special value to signal end
|
||||
NotifyAXThread();
|
||||
m_axthread.join();
|
||||
}
|
||||
|
||||
m_rMailHandler.Clear();
|
||||
}
|
||||
|
||||
void CUCode_AX::LoadResamplingCoefficients()
|
||||
{
|
||||
m_coeffs_available = false;
|
||||
|
||||
std::string filenames[] = {
|
||||
File::GetUserPath(D_GCUSER_IDX) + "dsp_coef.bin",
|
||||
File::GetSysDirectory() + "/GC/dsp_coef.bin"
|
||||
};
|
||||
|
||||
size_t fidx;
|
||||
std::string filename;
|
||||
for (fidx = 0; fidx < sizeof (filenames) / sizeof (filenames[0]); ++fidx)
|
||||
{
|
||||
filename = filenames[fidx];
|
||||
if (!File::Exists(filename))
|
||||
continue;
|
||||
|
||||
if (File::GetSize(filename) != 0x1000)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (fidx >= sizeof (filenames) / sizeof (filenames[0]))
|
||||
return;
|
||||
|
||||
WARN_LOG(DSPHLE, "Loading polyphase resampling coeffs from %s", filename.c_str());
|
||||
|
||||
FILE* fp = fopen(filename.c_str(), "rb");
|
||||
fread(m_coeffs, 1, 0x1000, fp);
|
||||
fclose(fp);
|
||||
|
||||
for (u32 i = 0; i < 0x800; ++i)
|
||||
m_coeffs[i] = Common::swap16(m_coeffs[i]);
|
||||
|
||||
m_coeffs_available = true;
|
||||
}
|
||||
|
||||
void CUCode_AX::SpawnAXThread(CUCode_AX* self)
|
||||
{
|
||||
self->AXThread();
|
||||
|
@ -61,20 +110,32 @@ void CUCode_AX::AXThread()
|
|||
m_processing.lock();
|
||||
HandleCommandList();
|
||||
m_cmdlist_size = 0;
|
||||
|
||||
// Signal end of processing
|
||||
m_rMailHandler.PushMail(DSP_YIELD);
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
SignalWorkEnd();
|
||||
m_processing.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AX::SignalWorkEnd()
|
||||
{
|
||||
// Signal end of processing
|
||||
m_rMailHandler.PushMail(DSP_YIELD);
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
}
|
||||
|
||||
void CUCode_AX::NotifyAXThread()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_cmdlist_mutex);
|
||||
m_cmdlist_cv.notify_one();
|
||||
}
|
||||
|
||||
void CUCode_AX::StartWorking()
|
||||
{
|
||||
if (m_run_on_thread)
|
||||
NotifyAXThread();
|
||||
else
|
||||
m_work_available = true;
|
||||
}
|
||||
|
||||
void CUCode_AX::HandleCommandList()
|
||||
{
|
||||
// Temp variables for addresses computation
|
||||
|
@ -200,11 +261,9 @@ void CUCode_AX::HandleCommandList()
|
|||
u16 idx = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
|
||||
// TODO
|
||||
(void)samp_val;
|
||||
(void)idx;
|
||||
|
||||
// suppress warnings:
|
||||
(void)samp_val; (void)idx;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -243,26 +302,25 @@ void CUCode_AX::HandleCommandList()
|
|||
}
|
||||
|
||||
default:
|
||||
ERROR_LOG(DSPHLE, "Unknown command in AX cmdlist: %04x", cmd);
|
||||
ERROR_LOG(DSPHLE, "Unknown command in AX command list: %04x", cmd);
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyUpdatesForMs(AXPB& pb, int curr_ms)
|
||||
void CUCode_AX::ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates)
|
||||
{
|
||||
u32 start_idx = 0;
|
||||
for (int i = 0; i < curr_ms; ++i)
|
||||
start_idx += pb.updates.num_updates[i];
|
||||
start_idx += num_updates[i];
|
||||
|
||||
u32 update_addr = HILO_TO_32(pb.updates.data);
|
||||
for (u32 i = start_idx; i < start_idx + pb.updates.num_updates[curr_ms]; ++i)
|
||||
for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i)
|
||||
{
|
||||
u16 update_off = HLEMemory_Read_U16(update_addr + 4 * i);
|
||||
u16 update_val = HLEMemory_Read_U16(update_addr + 4 * i + 2);
|
||||
u16 update_off = Common::swap16(updates[2 * i]);
|
||||
u16 update_val = Common::swap16(updates[2 * i + 1]);
|
||||
|
||||
((u16*)&pb)[update_off] = update_val;
|
||||
pb[update_off] = update_val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,11 +463,15 @@ void CUCode_AX::ProcessPBList(u32 pb_addr)
|
|||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
u32 updates_addr = HILO_TO_32(pb.updates.data);
|
||||
u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr);
|
||||
|
||||
for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
|
||||
{
|
||||
ApplyUpdatesForMs(pb, curr_ms);
|
||||
ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates);
|
||||
|
||||
Process1ms(pb, buffers, ConvertMixerControl(pb.mixer_control));
|
||||
ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control),
|
||||
m_coeffs_available ? m_coeffs : NULL);
|
||||
|
||||
// Forward the buffers
|
||||
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||
|
@ -599,6 +661,7 @@ void CUCode_AX::HandleMail(u32 mail)
|
|||
if (next_is_cmdlist)
|
||||
{
|
||||
CopyCmdList(mail, cmdlist_size);
|
||||
StartWorking();
|
||||
NotifyAXThread();
|
||||
}
|
||||
else if (m_UploadSetupInProgress)
|
||||
|
@ -667,6 +730,12 @@ void CUCode_AX::Update(int cycles)
|
|||
m_rMailHandler.PushMail(DSP_RESUME);
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
}
|
||||
else if (m_work_available)
|
||||
{
|
||||
HandleCommandList();
|
||||
m_cmdlist_size = 0;
|
||||
SignalWorkEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AX::DoAXState(PointerWrap& p)
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#define _UCODE_AX_H
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
|
||||
// We can't directly use the mixer_control field from the PB because it does
|
||||
// not mean the same in all AX versions. The AX UCode converts the
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
virtual void DoState(PointerWrap& p);
|
||||
|
||||
// Needed because StdThread.h std::thread implem does not support member
|
||||
// pointers.
|
||||
// pointers. TODO(delroth): obsolete.
|
||||
static void SpawnAXThread(CUCode_AX* self);
|
||||
|
||||
protected:
|
||||
|
@ -102,18 +102,31 @@ protected:
|
|||
int m_samples_auxB_right[32 * 5];
|
||||
int m_samples_auxB_surround[32 * 5];
|
||||
|
||||
// This flag is set if there is anything to process.
|
||||
bool m_work_available;
|
||||
|
||||
// Volatile because it's set by HandleMail and accessed in
|
||||
// HandleCommandList, which are running in two different threads.
|
||||
volatile u16 m_cmdlist[512];
|
||||
volatile u32 m_cmdlist_size;
|
||||
|
||||
std::thread m_axthread;
|
||||
bool m_run_on_thread;
|
||||
|
||||
// Sync objects
|
||||
std::mutex m_processing;
|
||||
std::condition_variable m_cmdlist_cv;
|
||||
std::mutex m_cmdlist_mutex;
|
||||
|
||||
std::thread m_axthread;
|
||||
|
||||
// Table of coefficients for polyphase sample rate conversion.
|
||||
// The coefficients aren't always available (they are part of the DSP DROM)
|
||||
// so we also need to know if they are valid or not.
|
||||
bool m_coeffs_available;
|
||||
s16 m_coeffs[0x800];
|
||||
|
||||
void LoadResamplingCoefficients();
|
||||
|
||||
// Copy a command list from memory to our temp buffer
|
||||
void CopyCmdList(u32 addr, u16 size);
|
||||
|
||||
|
@ -122,13 +135,21 @@ protected:
|
|||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
// Send a notification to the AX thread to tell him a new cmdlist addr is
|
||||
// Apply updates to a PB. Generic, used in AX GC and AX Wii.
|
||||
void ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates);
|
||||
|
||||
// Signal that we should start handling a command list. Dispatches to the
|
||||
// AX thread if using a thread, else just sets a boolean flag.
|
||||
void StartWorking();
|
||||
|
||||
// Send a notification to the AX thread to tell it a new cmdlist addr is
|
||||
// available for processing.
|
||||
void NotifyAXThread();
|
||||
|
||||
void AXThread();
|
||||
|
||||
virtual void HandleCommandList();
|
||||
void SignalWorkEnd();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb);
|
||||
|
|
|
@ -161,15 +161,15 @@ struct PBDpopWii
|
|||
|
||||
struct PBDpopWM
|
||||
{
|
||||
s16 aMain0;
|
||||
s16 aMain1;
|
||||
s16 aMain2;
|
||||
s16 aMain3;
|
||||
s16 main0;
|
||||
s16 main1;
|
||||
s16 main2;
|
||||
s16 main3;
|
||||
|
||||
s16 aAux0;
|
||||
s16 aAux1;
|
||||
s16 aAux2;
|
||||
s16 aAux3;
|
||||
s16 aux0;
|
||||
s16 aux1;
|
||||
s16 aux2;
|
||||
s16 aux3;
|
||||
};
|
||||
|
||||
struct PBVolumeEnvelope
|
||||
|
@ -211,13 +211,13 @@ struct PBSampleRateConverter
|
|||
u16 ratio_hi; // integer part of sampling ratio
|
||||
u16 ratio_lo; // fraction part of sampling ratio
|
||||
u16 cur_addr_frac;
|
||||
u16 last_samples[4];
|
||||
s16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBSampleRateConverterWM
|
||||
{
|
||||
u16 currentAddressFrac;
|
||||
u16 last_samples[4];
|
||||
u16 cur_addr_frac;
|
||||
s16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBADPCMLoopInfo
|
||||
|
@ -230,7 +230,7 @@ struct PBADPCMLoopInfo
|
|||
struct PBLowPassFilter
|
||||
{
|
||||
u16 enabled;
|
||||
u16 yn1;
|
||||
s16 yn1;
|
||||
u16 a0;
|
||||
u16 b0;
|
||||
};
|
||||
|
@ -324,52 +324,6 @@ struct AXPBWii
|
|||
u16 pad[12]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// Seems like nintendo used an early version of AXWii and forgot to remove the update functionality ;p
|
||||
struct PBUpdatesWiiSports
|
||||
{
|
||||
u16 num_updates[3];
|
||||
u16 data_hi;
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
struct AXPBWiiSports
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u32 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdatesWiiSports updates;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[7]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// TODO: All these enums have changed a lot for wii
|
||||
enum {
|
||||
AUDIOFORMAT_ADPCM = 0,
|
|
@ -21,247 +21,678 @@
|
|||
#include "Mixer.h"
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXWii_Structs.h"
|
||||
#include "UCode_AX.h" // for some functions in CUCode_AX
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AXWii.h"
|
||||
#include "UCode_AXWii_Voice.h"
|
||||
|
||||
#define AX_WII
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
|
||||
CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
: IUCode(dsp_hle, l_CRC)
|
||||
, m_addressPBs(0xFFFFFFFF)
|
||||
: CUCode_AX(dsp_hle, l_CRC),
|
||||
m_last_main_volume(0x8000)
|
||||
{
|
||||
// we got loaded
|
||||
m_rMailHandler.PushMail(DSP_INIT);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
m_last_aux_volumes[i] = 0x8000;
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii");
|
||||
|
||||
templbuffer = new int[1024 * 1024];
|
||||
temprbuffer = new int[1024 * 1024];
|
||||
|
||||
wiisportsHack = m_CRC == 0xfa450138;
|
||||
m_old_axwii = (l_CRC == 0xfa450138);
|
||||
}
|
||||
|
||||
CUCode_AXWii::~CUCode_AXWii()
|
||||
{
|
||||
m_rMailHandler.Clear();
|
||||
delete [] templbuffer;
|
||||
delete [] temprbuffer;
|
||||
}
|
||||
|
||||
void CUCode_AXWii::HandleMail(u32 _uMail)
|
||||
void CUCode_AXWii::HandleCommandList()
|
||||
{
|
||||
if (m_UploadSetupInProgress)
|
||||
// Temp variables for addresses computation
|
||||
u16 addr_hi, addr_lo;
|
||||
u16 addr2_hi, addr2_lo;
|
||||
u16 volume;
|
||||
|
||||
u32 pb_addr = 0;
|
||||
|
||||
// WARN_LOG(DSPHLE, "Command list:");
|
||||
// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
|
||||
// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
|
||||
// WARN_LOG(DSPHLE, "-------------");
|
||||
|
||||
u32 curr_idx = 0;
|
||||
bool end = false;
|
||||
while (!end)
|
||||
{
|
||||
PrepareBootUCode(_uMail);
|
||||
return;
|
||||
}
|
||||
else if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
|
||||
{
|
||||
// We are expected to get a new CmdBlock
|
||||
DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail);
|
||||
}
|
||||
else switch(_uMail)
|
||||
{
|
||||
case 0xCDD10000: // Action 0 - AX_ResumeTask()
|
||||
m_rMailHandler.PushMail(DSP_RESUME);
|
||||
break;
|
||||
u16 cmd = m_cmdlist[curr_idx++];
|
||||
|
||||
case 0xCDD10001: // Action 1 - new ucode upload
|
||||
DEBUG_LOG(DSPHLE,"DSP IROM - New Ucode!");
|
||||
// TODO find a better way to protect from HLEMixer?
|
||||
soundStream->GetMixer()->SetHLEReady(false);
|
||||
m_UploadSetupInProgress = true;
|
||||
break;
|
||||
if (m_old_axwii)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
// Some of these commands are unknown, or unused in this AX HLE.
|
||||
// We still need to skip their arguments using "curr_idx += N".
|
||||
|
||||
case 0xCDD10002: // Action 2 - IROM_Reset(); ( WII: De Blob, Cursed Mountain,...)
|
||||
DEBUG_LOG(DSPHLE,"DSP IROM - Reset!");
|
||||
m_DSPHLE->SetUCode(UCODE_ROM);
|
||||
return;
|
||||
case CMD_SETUP_OLD:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetupProcessing(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case 0xCDD10003: // Action 3 - AX_GetNextCmdBlock()
|
||||
break;
|
||||
case CMD_ADD_TO_LR_OLD:
|
||||
case CMD_SUB_TO_LR_OLD:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
AddToLR(HILO_TO_32(addr), cmd == CMD_SUB_TO_LR_OLD);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail);
|
||||
AXTask(_uMail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case CMD_ADD_SUB_TO_LR_OLD:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
AddSubToLR(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize)
|
||||
{
|
||||
AXPBWii PB;
|
||||
case CMD_PB_ADDR_OLD:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
pb_addr = HILO_TO_32(addr);
|
||||
break;
|
||||
|
||||
if (_iSize > 1024 * 1024)
|
||||
_iSize = 1024 * 1024;
|
||||
case CMD_PROCESS_OLD:
|
||||
ProcessPBList(pb_addr);
|
||||
break;
|
||||
|
||||
memset(templbuffer, 0, _iSize * sizeof(int));
|
||||
memset(temprbuffer, 0, _iSize * sizeof(int));
|
||||
case CMD_MIX_AUXA_OLD:
|
||||
case CMD_MIX_AUXB_OLD:
|
||||
case CMD_MIX_AUXC_OLD:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
MixAUXSamples(cmd - CMD_MIX_AUXA_OLD, HILO_TO_32(addr), HILO_TO_32(addr2), volume);
|
||||
break;
|
||||
|
||||
u32 blockAddr = m_addressPBs;
|
||||
if (!blockAddr)
|
||||
return;
|
||||
case CMD_UPL_AUXA_MIX_LRSC_OLD:
|
||||
case CMD_UPL_AUXB_MIX_LRSC_OLD:
|
||||
{
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
u32 addresses[6] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
(u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9],
|
||||
(u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11],
|
||||
};
|
||||
curr_idx += 12;
|
||||
UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC_OLD, addresses, volume);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_PBS; i++)
|
||||
{
|
||||
if (!ReadPB(blockAddr, PB))
|
||||
break;
|
||||
// TODO(delroth): figure this one out, it's used by almost every
|
||||
// game I've tested so far.
|
||||
case CMD_UNK_0B_OLD: curr_idx += 4; break;
|
||||
|
||||
if (wiisportsHack)
|
||||
MixAddVoice(*(AXPBWiiSports*)&PB, templbuffer, temprbuffer, _iSize);
|
||||
case CMD_OUTPUT_OLD:
|
||||
case CMD_OUTPUT_DPL2_OLD:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), 0x8000,
|
||||
cmd == CMD_OUTPUT_DPL2_OLD);
|
||||
break;
|
||||
|
||||
case CMD_WM_OUTPUT_OLD:
|
||||
{
|
||||
u32 addresses[4] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
};
|
||||
curr_idx += 8;
|
||||
OutputWMSamples(addresses);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_END_OLD:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
MixAddVoice(PB, templbuffer, temprbuffer, _iSize);
|
||||
|
||||
if (!WritePB(blockAddr, PB))
|
||||
break;
|
||||
|
||||
// next PB, or done
|
||||
blockAddr = (PB.next_pb_hi << 16) | PB.next_pb_lo;
|
||||
if (!blockAddr)
|
||||
break;
|
||||
}
|
||||
|
||||
// We write the sound to _pBuffer
|
||||
if (_pBuffer)
|
||||
{
|
||||
for (int i = 0; i < _iSize; i++)
|
||||
{
|
||||
// Clamp into 16-bit. Maybe we should add a volume compressor here.
|
||||
int left = templbuffer[i] + _pBuffer[0];
|
||||
int right = temprbuffer[i] + _pBuffer[1];
|
||||
if (left < -32767) left = -32767;
|
||||
else if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
else if (right > 32767) right = 32767;
|
||||
*_pBuffer++ = left;
|
||||
*_pBuffer++ = right;
|
||||
switch (cmd)
|
||||
{
|
||||
// Some of these commands are unknown, or unused in this AX HLE.
|
||||
// We still need to skip their arguments using "curr_idx += N".
|
||||
|
||||
case CMD_SETUP:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetupProcessing(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_ADD_TO_LR:
|
||||
case CMD_SUB_TO_LR:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
AddToLR(HILO_TO_32(addr), cmd == CMD_SUB_TO_LR);
|
||||
break;
|
||||
|
||||
case CMD_ADD_SUB_TO_LR:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
AddSubToLR(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_PROCESS:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
ProcessPBList(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_MIX_AUXA:
|
||||
case CMD_MIX_AUXB:
|
||||
case CMD_MIX_AUXC:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume);
|
||||
break;
|
||||
|
||||
case CMD_UPL_AUXA_MIX_LRSC:
|
||||
case CMD_UPL_AUXB_MIX_LRSC:
|
||||
{
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
u32 addresses[6] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
(u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9],
|
||||
(u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11],
|
||||
};
|
||||
curr_idx += 12;
|
||||
UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC, addresses, volume);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(delroth): figure this one out, it's used by almost every
|
||||
// game I've tested so far.
|
||||
case CMD_UNK_0A: curr_idx += 4; break;
|
||||
|
||||
case CMD_OUTPUT:
|
||||
case CMD_OUTPUT_DPL2:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume,
|
||||
cmd == CMD_OUTPUT_DPL2);
|
||||
break;
|
||||
|
||||
case CMD_WM_OUTPUT:
|
||||
{
|
||||
u32 addresses[4] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
};
|
||||
curr_idx += 8;
|
||||
OutputWMSamples(addresses);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_END:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CUCode_AXWii::Update(int cycles)
|
||||
void CUCode_AXWii::SetupProcessing(u32 init_addr)
|
||||
{
|
||||
if (NeedsResumeMail())
|
||||
// TODO: should be easily factorizable with AX
|
||||
s16 init_data[60];
|
||||
|
||||
for (u32 i = 0; i < 60; ++i)
|
||||
init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
|
||||
|
||||
// List of all buffers we have to initialize
|
||||
struct {
|
||||
int* ptr;
|
||||
u32 samples;
|
||||
} buffers[] = {
|
||||
{ m_samples_left, 32 },
|
||||
{ m_samples_right, 32 },
|
||||
{ m_samples_surround, 32 },
|
||||
{ m_samples_auxA_left, 32 },
|
||||
{ m_samples_auxA_right, 32 },
|
||||
{ m_samples_auxA_surround, 32 },
|
||||
{ m_samples_auxB_left, 32 },
|
||||
{ m_samples_auxB_right, 32 },
|
||||
{ m_samples_auxB_surround, 32 },
|
||||
{ m_samples_auxC_left, 32 },
|
||||
{ m_samples_auxC_right, 32 },
|
||||
{ m_samples_auxC_surround, 32 },
|
||||
|
||||
{ m_samples_wm0, 6 },
|
||||
{ m_samples_aux0, 6 },
|
||||
{ m_samples_wm1, 6 },
|
||||
{ m_samples_aux1, 6 },
|
||||
{ m_samples_wm2, 6 },
|
||||
{ m_samples_aux2, 6 },
|
||||
{ m_samples_wm3, 6 },
|
||||
{ m_samples_aux3, 6 }
|
||||
};
|
||||
|
||||
u32 init_idx = 0;
|
||||
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
|
||||
{
|
||||
m_rMailHandler.PushMail(DSP_RESUME);
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
}
|
||||
// check if we have to send something
|
||||
else if (!m_rMailHandler.IsEmpty())
|
||||
{
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
|
||||
s16 delta = (s16)init_data[init_idx + 2];
|
||||
|
||||
init_idx += 3;
|
||||
|
||||
if (!init_val)
|
||||
memset(buffers[i].ptr, 0, 3 * buffers[i].samples * sizeof (int));
|
||||
else
|
||||
{
|
||||
for (u32 j = 0; j < 3 * buffers[i].samples; ++j)
|
||||
{
|
||||
buffers[i].ptr[j] = init_val;
|
||||
init_val += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AX seems to bootup one task only and waits for resume-callbacks
|
||||
// everytime the DSP has "spare time" it sends a resume-mail to the CPU
|
||||
// and the __DSPHandler calls a AX-Callback which generates a new AXFrame
|
||||
bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
void CUCode_AXWii::AddToLR(u32 val_addr, bool neg)
|
||||
{
|
||||
u32 uAddress = _uMail;
|
||||
//u32 Addr__AXStudio;
|
||||
//u32 Addr__AXOutSBuffer;
|
||||
bool bExecuteList = true;
|
||||
|
||||
/*
|
||||
for (int i=0;i<64;i++) {
|
||||
NOTICE_LOG(DSPHLE,"%x - %08x",uAddress+(i*4),HLEMemory_Read_U32(uAddress+(i*4)));
|
||||
}
|
||||
*/
|
||||
|
||||
while (bExecuteList)
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
|
||||
for (int i = 0; i < 32 * 3; ++i)
|
||||
{
|
||||
u16 iCommand = HLEMemory_Read_U16(uAddress);
|
||||
uAddress += 2;
|
||||
//NOTICE_LOG(DSPHLE,"AXWII - AXLIST CMD %X",iCommand);
|
||||
int val = (int)Common::swap32(*ptr++);
|
||||
if (neg)
|
||||
val = -val;
|
||||
|
||||
switch (iCommand)
|
||||
{
|
||||
case 0x0000:
|
||||
//Addr__AXStudio = HLEMemory_Read_U32(uAddress);
|
||||
uAddress += 4;
|
||||
break;
|
||||
m_samples_left[i] += val;
|
||||
m_samples_right[i] += val;
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0001:
|
||||
uAddress += 4;
|
||||
break;
|
||||
void CUCode_AXWii::AddSubToLR(u32 val_addr)
|
||||
{
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
|
||||
for (int i = 0; i < 32 * 3; ++i)
|
||||
{
|
||||
int val = (int)Common::swap32(*ptr++);
|
||||
m_samples_left[i] += val;
|
||||
}
|
||||
for (int i = 0; i < 32 * 3; ++i)
|
||||
{
|
||||
int val = (int)Common::swap32(*ptr++);
|
||||
m_samples_right[i] -= val;
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0003:
|
||||
uAddress += 4;
|
||||
break;
|
||||
AXMixControl CUCode_AXWii::ConvertMixerControl(u32 mixer_control)
|
||||
{
|
||||
u32 ret = 0;
|
||||
|
||||
case 0x0004:
|
||||
// PBs are here now
|
||||
m_addressPBs = HLEMemory_Read_U32(uAddress);
|
||||
if (soundStream)
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
// soundStream->Update();
|
||||
uAddress += 4;
|
||||
break;
|
||||
if (mixer_control & 0x00000001) ret |= MIX_L;
|
||||
if (mixer_control & 0x00000002) ret |= MIX_R;
|
||||
if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
|
||||
if (mixer_control & 0x00000008) ret |= MIX_S;
|
||||
if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
|
||||
if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
|
||||
if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
|
||||
if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
|
||||
if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
|
||||
if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
|
||||
if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
|
||||
if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
|
||||
if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
|
||||
if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
|
||||
if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
|
||||
if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
|
||||
if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
|
||||
if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
|
||||
if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
|
||||
if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
|
||||
|
||||
case 0x0005:
|
||||
if (!wiisportsHack)
|
||||
uAddress += 10;
|
||||
break;
|
||||
return (AXMixControl)ret;
|
||||
}
|
||||
|
||||
case 0x0006:
|
||||
uAddress += 10;
|
||||
break;
|
||||
void CUCode_AXWii::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals)
|
||||
{
|
||||
float curr = vol1;
|
||||
for (size_t i = 0; i < nvals; ++i)
|
||||
{
|
||||
curr += (vol2 - vol1) / (float)nvals;
|
||||
output[i] = curr;
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0007: // AXLIST_SBUFFER
|
||||
//Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress);
|
||||
uAddress += 10;
|
||||
break;
|
||||
bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates,
|
||||
u32* updates_addr)
|
||||
{
|
||||
u16* pb_mem = (u16*)&pb;
|
||||
|
||||
case 0x0008:
|
||||
uAddress += 26;
|
||||
break;
|
||||
if (!m_old_axwii)
|
||||
return false;
|
||||
|
||||
case 0x000a:
|
||||
uAddress += wiisportsHack ? 4 : 8; // AXLIST_COMPRESSORTABLE
|
||||
break;
|
||||
// Copy the num_updates field.
|
||||
memcpy(num_updates, pb_mem + 41, 6);
|
||||
|
||||
case 0x000b:
|
||||
uAddress += wiisportsHack ? 2 : 10;
|
||||
break;
|
||||
// Get the address of the updates data
|
||||
u16 addr_hi = pb_mem[44];
|
||||
u16 addr_lo = pb_mem[45];
|
||||
u32 addr = HILO_TO_32(addr);
|
||||
u16* ptr = (u16*)HLEMemory_Get_Pointer(addr);
|
||||
|
||||
case 0x000c:
|
||||
uAddress += wiisportsHack ? 8 : 10;
|
||||
break;
|
||||
*updates_addr = addr;
|
||||
|
||||
case 0x000d:
|
||||
uAddress += 16;
|
||||
break;
|
||||
// Copy the updates data and change the offset to match a PB without
|
||||
// updates data.
|
||||
u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2];
|
||||
for (u32 i = 0; i < updates_count; ++i)
|
||||
{
|
||||
u16 update_off = Common::swap16(ptr[2 * i]);
|
||||
u16 update_val = Common::swap16(ptr[2 * i + 1]);
|
||||
|
||||
case 0x000e:
|
||||
if (wiisportsHack)
|
||||
uAddress += 16;
|
||||
else
|
||||
bExecuteList = false;
|
||||
break;
|
||||
if (update_off > 45)
|
||||
update_off -= 5;
|
||||
|
||||
case 0x000f: // only for Wii Sports uCode
|
||||
bExecuteList = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
INFO_LOG(DSPHLE,"DSPHLE - AXwii - AXLIST - Unknown CMD: %x",iCommand);
|
||||
// unknown command so stop the execution of this TaskList
|
||||
bExecuteList = false;
|
||||
break;
|
||||
}
|
||||
updates[2 * i] = update_off;
|
||||
updates[2 * i + 1] = update_val;
|
||||
}
|
||||
|
||||
m_rMailHandler.PushMail(DSP_YIELD); //its here in case there is a CMD fuckup
|
||||
// Remove the updates data from the PB
|
||||
memmove(pb_mem + 41, pb_mem + 46, sizeof (pb) - 2 * 46);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CUCode_AXWii::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr)
|
||||
{
|
||||
u16* pb_mem = (u16*)&pb;
|
||||
|
||||
// Make some space
|
||||
memmove(pb_mem + 46, pb_mem + 41, sizeof (pb) - 2 * 46);
|
||||
|
||||
// Reinsert previous values
|
||||
pb_mem[41] = num_updates[0];
|
||||
pb_mem[42] = num_updates[1];
|
||||
pb_mem[43] = num_updates[2];
|
||||
pb_mem[44] = updates_addr >> 16;
|
||||
pb_mem[45] = updates_addr & 0xFFFF;
|
||||
}
|
||||
|
||||
void CUCode_AXWii::ProcessPBList(u32 pb_addr)
|
||||
{
|
||||
AXPBWii pb;
|
||||
|
||||
while (pb_addr)
|
||||
{
|
||||
AXBuffers buffers = {{
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround,
|
||||
m_samples_auxA_left,
|
||||
m_samples_auxA_right,
|
||||
m_samples_auxA_surround,
|
||||
m_samples_auxB_left,
|
||||
m_samples_auxB_right,
|
||||
m_samples_auxB_surround,
|
||||
m_samples_auxC_left,
|
||||
m_samples_auxC_right,
|
||||
m_samples_auxC_surround,
|
||||
m_samples_wm0,
|
||||
m_samples_aux0,
|
||||
m_samples_wm1,
|
||||
m_samples_aux1,
|
||||
m_samples_wm2,
|
||||
m_samples_aux2,
|
||||
m_samples_wm3,
|
||||
m_samples_aux3
|
||||
}};
|
||||
|
||||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
u16 num_updates[3];
|
||||
u16 updates[1024];
|
||||
u32 updates_addr;
|
||||
if (ExtractUpdatesFields(pb, num_updates, updates, &updates_addr))
|
||||
{
|
||||
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
|
||||
{
|
||||
ApplyUpdatesForMs(curr_ms, (u16*)&pb, num_updates, updates);
|
||||
ProcessVoice(pb, buffers, 32,
|
||||
ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
|
||||
m_coeffs_available ? m_coeffs : NULL);
|
||||
|
||||
// Forward the buffers
|
||||
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||
buffers.ptrs[i] += 32;
|
||||
}
|
||||
ReinjectUpdatesFields(pb, num_updates, updates_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessVoice(pb, buffers, 96,
|
||||
ConvertMixerControl(HILO_TO_32(pb.mixer_control)),
|
||||
m_coeffs_available ? m_coeffs : NULL);
|
||||
}
|
||||
|
||||
WritePB(pb_addr, pb);
|
||||
pb_addr = HILO_TO_32(pb.next_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume)
|
||||
{
|
||||
u16 volume_ramp[96];
|
||||
GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96);
|
||||
m_last_aux_volumes[aux_id] = volume;
|
||||
|
||||
int* buffers[3] = { 0 };
|
||||
int* main_buffers[3] = {
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround
|
||||
};
|
||||
|
||||
switch (aux_id)
|
||||
{
|
||||
case 0:
|
||||
buffers[0] = m_samples_auxA_left;
|
||||
buffers[1] = m_samples_auxA_right;
|
||||
buffers[2] = m_samples_auxA_surround;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffers[0] = m_samples_auxB_left;
|
||||
buffers[1] = m_samples_auxB_right;
|
||||
buffers[2] = m_samples_auxB_surround;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffers[0] = m_samples_auxC_left;
|
||||
buffers[1] = m_samples_auxC_right;
|
||||
buffers[2] = m_samples_auxC_surround;
|
||||
break;
|
||||
}
|
||||
|
||||
// Send the content of AUX buffers to the CPU
|
||||
if (write_addr)
|
||||
{
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
*ptr++ = Common::swap32(buffers[i][j]);
|
||||
}
|
||||
|
||||
// Then read the buffers from the CPU and add to our main buffers.
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
{
|
||||
s64 sample = (s64)(s32)Common::swap32(*ptr++);
|
||||
sample *= volume_ramp[j];
|
||||
main_buffers[i][j] += (s32)(sample >> 15);
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AXWii::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume)
|
||||
{
|
||||
int* aux_left = aux_id ? m_samples_auxB_left : m_samples_auxA_left;
|
||||
int* aux_right = aux_id ? m_samples_auxB_right : m_samples_auxA_right;
|
||||
int* aux_surround = aux_id ? m_samples_auxB_surround : m_samples_auxA_surround;
|
||||
int* auxc_buffer = aux_id ? m_samples_auxC_surround : m_samples_auxC_right;
|
||||
|
||||
int* upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[0]);
|
||||
for (u32 i = 0; i < 96; ++i)
|
||||
*upload_ptr++ = Common::swap32(aux_left[i]);
|
||||
for (u32 i = 0; i < 96; ++i)
|
||||
*upload_ptr++ = Common::swap32(aux_right[i]);
|
||||
for (u32 i = 0; i < 96; ++i)
|
||||
*upload_ptr++ = Common::swap32(aux_surround[i]);
|
||||
|
||||
upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[1]);
|
||||
for (u32 i = 0; i < 96; ++i)
|
||||
*upload_ptr++ = Common::swap32(auxc_buffer[i]);
|
||||
|
||||
u16 volume_ramp[96];
|
||||
GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96);
|
||||
m_last_aux_volumes[aux_id] = volume;
|
||||
|
||||
int* mix_dest[4] = {
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround,
|
||||
m_samples_auxC_left
|
||||
};
|
||||
for (u32 mix_i = 0; mix_i < 4; ++mix_i)
|
||||
{
|
||||
int* dl_ptr = (int*)HLEMemory_Get_Pointer(addresses[2 + mix_i]);
|
||||
for (u32 i = 0; i < 96; ++i)
|
||||
aux_left[i] = Common::swap32(dl_ptr[i]);
|
||||
|
||||
for (u32 i = 0; i < 96; ++i)
|
||||
{
|
||||
s64 sample = (s64)(s32)aux_left[i];
|
||||
sample *= volume_ramp[i];
|
||||
mix_dest[mix_i][i] += (s32)(sample >> 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume,
|
||||
bool upload_auxc)
|
||||
{
|
||||
u16 volume_ramp[96];
|
||||
GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, 96);
|
||||
m_last_main_volume = volume;
|
||||
|
||||
int upload_buffer[3 * 32] = { 0 };
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
upload_buffer[i] = Common::swap32(m_samples_surround[i]);
|
||||
memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer));
|
||||
|
||||
if (upload_auxc)
|
||||
{
|
||||
surround_addr += sizeof (upload_buffer);
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]);
|
||||
memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer));
|
||||
}
|
||||
|
||||
short buffer[3 * 32 * 2];
|
||||
|
||||
// Clamp internal buffers to 16 bits.
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
int left = m_samples_left[i];
|
||||
int right = m_samples_right[i];
|
||||
|
||||
// Apply global volume. Cast to s64 to avoid overflow.
|
||||
left = ((s64)left * volume_ramp[i]) >> 15;
|
||||
right = ((s64)right * volume_ramp[i]) >> 15;
|
||||
|
||||
if (left < -32767) left = -32767;
|
||||
if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
if (right > 32767) right = 32767;
|
||||
|
||||
m_samples_left[i] = left;
|
||||
m_samples_right[i] = right;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
buffer[2 * i] = Common::swap16(m_samples_right[i]);
|
||||
buffer[2 * i + 1] = Common::swap16(m_samples_left[i]);
|
||||
}
|
||||
|
||||
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
|
||||
|
||||
// There should be a DSP_SYNC message sent here. However, it looks like not
|
||||
// sending it does not cause any issue, and sending it actually causes some
|
||||
// sounds to go at half speed. I have no idea why.
|
||||
}
|
||||
|
||||
void CUCode_AXWii::OutputWMSamples(u32* addresses)
|
||||
{
|
||||
int* buffers[] = {
|
||||
m_samples_wm0,
|
||||
m_samples_wm1,
|
||||
m_samples_wm2,
|
||||
m_samples_wm3
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
{
|
||||
int* in = buffers[i];
|
||||
u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
|
||||
for (u32 j = 0; j < 3 * 6; ++j)
|
||||
{
|
||||
int sample = in[j];
|
||||
if (sample < -32767) sample = -32767;
|
||||
if (sample > 32767) sample = 32767;
|
||||
out[j] = Common::swap16((u16)sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AXWii::DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_csMix);
|
||||
|
||||
p.Do(m_addressPBs);
|
||||
p.Do(wiisportsHack);
|
||||
std::lock_guard<std::mutex> lk(m_processing);
|
||||
|
||||
DoStateShared(p);
|
||||
DoAXState(p);
|
||||
|
||||
p.Do(m_samples_auxC_left);
|
||||
p.Do(m_samples_auxC_right);
|
||||
p.Do(m_samples_auxC_surround);
|
||||
|
||||
p.Do(m_samples_wm0);
|
||||
p.Do(m_samples_wm1);
|
||||
p.Do(m_samples_wm2);
|
||||
p.Do(m_samples_wm3);
|
||||
|
||||
p.Do(m_samples_aux0);
|
||||
p.Do(m_samples_aux1);
|
||||
p.Do(m_samples_aux2);
|
||||
p.Do(m_samples_aux3);
|
||||
|
||||
p.Do(m_last_main_volume);
|
||||
p.Do(m_last_aux_volumes);
|
||||
}
|
||||
|
|
|
@ -12,44 +12,116 @@
|
|||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AXWII
|
||||
#define _UCODE_AXWII
|
||||
#ifndef _UCODE_AXWII_H
|
||||
#define _UCODE_AXWII_H
|
||||
|
||||
#include "UCode_AXWii_Structs.h"
|
||||
#include "UCode_AX.h"
|
||||
|
||||
#define NUMBER_OF_PBS 128
|
||||
|
||||
class CUCode_AXWii : public IUCode
|
||||
class CUCode_AXWii : public CUCode_AX
|
||||
{
|
||||
public:
|
||||
CUCode_AXWii(DSPHLE *dsp_hle, u32 _CRC);
|
||||
virtual ~CUCode_AXWii();
|
||||
|
||||
void HandleMail(u32 _uMail);
|
||||
void MixAdd(short* _pBuffer, int _iSize);
|
||||
void Update(int cycles);
|
||||
void DoState(PointerWrap &p);
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
protected:
|
||||
// Additional AUX buffers
|
||||
int m_samples_auxC_left[32 * 3];
|
||||
int m_samples_auxC_right[32 * 3];
|
||||
int m_samples_auxC_surround[32 * 3];
|
||||
|
||||
// Wiimote buffers
|
||||
int m_samples_wm0[6 * 3];
|
||||
int m_samples_aux0[6 * 3];
|
||||
int m_samples_wm1[6 * 3];
|
||||
int m_samples_aux1[6 * 3];
|
||||
int m_samples_wm2[6 * 3];
|
||||
int m_samples_aux2[6 * 3];
|
||||
int m_samples_wm3[6 * 3];
|
||||
int m_samples_aux3[6 * 3];
|
||||
|
||||
// Are we implementing an old version of AXWii which still has updates?
|
||||
bool m_old_axwii;
|
||||
|
||||
// Last volume values for MAIN and AUX. Used to generate volume ramps to
|
||||
// interpolate nicely between old and new volume values.
|
||||
u16 m_last_main_volume;
|
||||
u16 m_last_aux_volumes[3];
|
||||
|
||||
// If needed, extract the updates related fields from a PB. We need to
|
||||
// reinject them afterwards so that the correct PB typs is written to RAM.
|
||||
bool ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates,
|
||||
u32* updates_addr);
|
||||
void ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr);
|
||||
|
||||
// Convert a mixer_control bitfield to our internal representation for that
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
// Generate a volume ramp from vol1 to vol2, interpolating n volume values.
|
||||
// Uses floating point arithmetic, which isn't exactly what the UCode does,
|
||||
// but this gives better precision and nicer code.
|
||||
void GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals);
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void AddToLR(u32 val_addr, bool neg);
|
||||
void AddSubToLR(u32 val_addr);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume);
|
||||
void UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume);
|
||||
void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume,
|
||||
bool upload_auxc);
|
||||
void OutputWMSamples(u32* addresses); // 4 addresses
|
||||
|
||||
private:
|
||||
enum
|
||||
enum CmdType
|
||||
{
|
||||
MAIL_AX_ALIST = 0xBABE0000,
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_ADD_TO_LR = 0x01,
|
||||
CMD_SUB_TO_LR = 0x02,
|
||||
CMD_ADD_SUB_TO_LR = 0x03,
|
||||
CMD_PROCESS = 0x04,
|
||||
CMD_MIX_AUXA = 0x05,
|
||||
CMD_MIX_AUXB = 0x06,
|
||||
CMD_MIX_AUXC = 0x07,
|
||||
CMD_UPL_AUXA_MIX_LRSC = 0x08,
|
||||
CMD_UPL_AUXB_MIX_LRSC = 0x09,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_OUTPUT = 0x0B,
|
||||
CMD_OUTPUT_DPL2 = 0x0C,
|
||||
CMD_WM_OUTPUT = 0x0D,
|
||||
CMD_END = 0x0E,
|
||||
};
|
||||
|
||||
// PBs
|
||||
u32 m_addressPBs;
|
||||
|
||||
bool wiisportsHack;
|
||||
|
||||
int *templbuffer;
|
||||
int *temprbuffer;
|
||||
|
||||
// ax task message handler
|
||||
bool AXTask(u32& _uMail);
|
||||
void SendMail(u32 _uMail);
|
||||
// A lot of these are similar to the new version, but there is an offset in
|
||||
// the command ids due to the PB_ADDR command (which was removed from the
|
||||
// new AXWii).
|
||||
enum CmdTypeOld
|
||||
{
|
||||
CMD_SETUP_OLD = 0x00,
|
||||
CMD_ADD_TO_LR_OLD = 0x01,
|
||||
CMD_SUB_TO_LR_OLD = 0x02,
|
||||
CMD_ADD_SUB_TO_LR_OLD = 0x03,
|
||||
CMD_PB_ADDR_OLD = 0x04,
|
||||
CMD_PROCESS_OLD = 0x05,
|
||||
CMD_MIX_AUXA_OLD = 0x06,
|
||||
CMD_MIX_AUXB_OLD = 0x07,
|
||||
CMD_MIX_AUXC_OLD = 0x08,
|
||||
CMD_UPL_AUXA_MIX_LRSC_OLD = 0x09,
|
||||
CMD_UPL_AUXB_MIX_LRSC_OLD = 0x0a,
|
||||
CMD_UNK_0B_OLD = 0x0B,
|
||||
CMD_OUTPUT_OLD = 0x0C, // no volume!
|
||||
CMD_OUTPUT_DPL2_OLD = 0x0D,
|
||||
CMD_WM_OUTPUT_OLD = 0x0E,
|
||||
CMD_END_OLD = 0x0F
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _UCODE_AXWII
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AX_ADPCM_H
|
||||
#define _UCODE_AX_ADPCM_H
|
||||
|
||||
#include "../../DSP.h"
|
||||
|
||||
static inline s16 ADPCM_Step(PBADPCMInfo &adpcm, u32& samplePos, u32 newSamplePos, u16 frac)
|
||||
{
|
||||
while (samplePos < newSamplePos)
|
||||
{
|
||||
if ((samplePos & 15) == 0)
|
||||
{
|
||||
adpcm.pred_scale = DSP::ReadARAM((samplePos & ~15) >> 1);
|
||||
samplePos += 2;
|
||||
newSamplePos += 2;
|
||||
}
|
||||
|
||||
int scale = 1 << (adpcm.pred_scale & 0xF);
|
||||
int coef_idx = (adpcm.pred_scale >> 4) & 7;
|
||||
|
||||
s32 coef1 = adpcm.coefs[coef_idx * 2 + 0];
|
||||
s32 coef2 = adpcm.coefs[coef_idx * 2 + 1];
|
||||
|
||||
int temp = (samplePos & 1) ?
|
||||
(DSP::ReadARAM(samplePos >> 1) & 0xF) :
|
||||
(DSP::ReadARAM(samplePos >> 1) >> 4);
|
||||
|
||||
if (temp >= 8)
|
||||
temp -= 16;
|
||||
|
||||
// 0x400 = 0.5 in 11-bit fixed point
|
||||
int val = (scale * temp) + ((0x400 + coef1 * adpcm.yn1 + coef2 * adpcm.yn2) >> 11);
|
||||
|
||||
if (val > 0x7FFF)
|
||||
val = 0x7FFF;
|
||||
else if (val < -0x7FFF)
|
||||
val = -0x7FFF;
|
||||
|
||||
adpcm.yn2 = adpcm.yn1;
|
||||
adpcm.yn1 = val;
|
||||
|
||||
samplePos++;
|
||||
}
|
||||
|
||||
return adpcm.yn1;
|
||||
}
|
||||
|
||||
// TODO: WTF is going on here?!?
|
||||
// Volume control (ramping)
|
||||
static inline u16 ADPCM_Vol(u16 vol, u16 delta)
|
||||
{
|
||||
int x = vol;
|
||||
if (delta && delta < 0x5000)
|
||||
x += delta * 20 * 8; // unsure what the right step is
|
||||
//x += 1 * 20 * 8;
|
||||
else if (delta && delta > 0x5000)
|
||||
//x -= (0x10000 - delta); // this is to small, it's often 1
|
||||
x -= (0x10000 - delta) * 20 * 16; // if this was 20 * 8 the sounds in Fire Emblem and Paper Mario
|
||||
// did not have time to go to zero before the were closed
|
||||
//x -= 1 * 20 * 16;
|
||||
|
||||
// make lower limits
|
||||
if (x < 0) x = 0;
|
||||
//if (pb.mixer_control < 1000 && x < pb.mixer_control) x = pb.mixer_control; // does this make
|
||||
// any sense?
|
||||
|
||||
// make upper limits
|
||||
//if (mixer_control > 1000 && x > mixer_control) x = mixer_control; // maybe mixer_control also
|
||||
// has a volume target?
|
||||
//if (x >= 0x7fff) x = 0x7fff; // this seems a little high
|
||||
//if (x >= 0x4e20) x = 0x4e20; // add a definitive limit at 20 000
|
||||
if (x >= 0x8000) x = 0x8000; // clamp to 32768;
|
||||
return x; // update volume
|
||||
}
|
||||
|
||||
#endif // _UCODE_AX_ADPCM_H
|
|
@ -1,365 +0,0 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AX_STRUCTS_H
|
||||
#define _UCODE_AX_STRUCTS_H
|
||||
|
||||
struct PBMixer
|
||||
{
|
||||
u16 left;
|
||||
u16 left_delta;
|
||||
u16 right;
|
||||
u16 right_delta;
|
||||
|
||||
u16 unknown3[8];
|
||||
u16 unknown4[6];
|
||||
};
|
||||
|
||||
struct PBMixerWii
|
||||
{
|
||||
// volume mixing values in .15, 0x8000 = ca. 1.0
|
||||
u16 left;
|
||||
u16 left_delta;
|
||||
u16 right;
|
||||
u16 right_delta;
|
||||
|
||||
u16 auxA_left;
|
||||
u16 auxA_left_delta;
|
||||
u16 auxA_right;
|
||||
u16 auxA_right_delta;
|
||||
|
||||
u16 auxB_left;
|
||||
u16 auxB_left_delta;
|
||||
u16 auxB_right;
|
||||
u16 auxB_right_delta;
|
||||
|
||||
// Note: the following elements usage changes a little in DPL2 mode
|
||||
// TODO: implement and comment it in the mixer
|
||||
u16 auxC_left;
|
||||
u16 auxC_left_delta;
|
||||
u16 auxC_right;
|
||||
u16 auxC_right_delta;
|
||||
|
||||
u16 surround;
|
||||
u16 surround_delta;
|
||||
u16 auxA_surround;
|
||||
u16 auxA_surround_delta;
|
||||
u16 auxB_surround;
|
||||
u16 auxB_surround_delta;
|
||||
u16 auxC_surround;
|
||||
u16 auxC_surround_delta;
|
||||
};
|
||||
|
||||
struct PBMixerWM
|
||||
{
|
||||
u16 main0;
|
||||
u16 main0_delta;
|
||||
u16 aux0;
|
||||
u16 aux0_delta;
|
||||
|
||||
u16 main1;
|
||||
u16 main1_delta;
|
||||
u16 aux1;
|
||||
u16 aux1_delta;
|
||||
|
||||
u16 main2;
|
||||
u16 main2_delta;
|
||||
u16 aux2;
|
||||
u16 aux2_delta;
|
||||
|
||||
u16 main3;
|
||||
u16 main3_delta;
|
||||
u16 aux3;
|
||||
u16 aux3_delta;
|
||||
};
|
||||
|
||||
struct PBInitialTimeDelay
|
||||
{
|
||||
u16 on;
|
||||
u16 addrMemHigh;
|
||||
u16 addrMemLow;
|
||||
u16 offsetLeft;
|
||||
u16 offsetRight;
|
||||
u16 targetLeft;
|
||||
u16 targetRight;
|
||||
};
|
||||
|
||||
// Update data - read these each 1ms subframe and use them!
|
||||
// It seems that to provide higher time precisions for MIDI events, some games
|
||||
// use this thing to update the parameter blocks per 1ms sub-block (a block is 5ms).
|
||||
// Using this data should fix games that are missing MIDI notes.
|
||||
struct PBUpdates
|
||||
{
|
||||
u16 num_updates[5];
|
||||
u16 data_hi; // These point to main RAM. Not sure about the structure of the data.
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
// The DSP stores the final sample values for each voice after every frame of processing.
|
||||
// The values are then accumulated for all dropped voices, added to the next frame of audio,
|
||||
// and ramped down on a per-sample basis to provide a gentle "roll off."
|
||||
struct PBDpop
|
||||
{
|
||||
s16 unknown[9];
|
||||
};
|
||||
|
||||
struct PBDpopWii
|
||||
{
|
||||
s16 left;
|
||||
s16 auxA_left;
|
||||
s16 auxB_left;
|
||||
s16 auxC_left;
|
||||
|
||||
s16 right;
|
||||
s16 auxA_right;
|
||||
s16 auxB_right;
|
||||
s16 auxC_right;
|
||||
|
||||
s16 surround;
|
||||
s16 auxA_surround;
|
||||
s16 auxB_surround;
|
||||
s16 auxC_surround;
|
||||
};
|
||||
|
||||
struct PBDpopWM
|
||||
{
|
||||
s16 aMain0;
|
||||
s16 aMain1;
|
||||
s16 aMain2;
|
||||
s16 aMain3;
|
||||
|
||||
s16 aAux0;
|
||||
s16 aAux1;
|
||||
s16 aAux2;
|
||||
s16 aAux3;
|
||||
};
|
||||
|
||||
struct PBVolumeEnvelope
|
||||
{
|
||||
u16 cur_volume; // volume at start of frame
|
||||
s16 cur_volume_delta; // signed per sample delta (96 samples per frame)
|
||||
};
|
||||
|
||||
struct PBUnknown2
|
||||
{
|
||||
u16 unknown_reserved[3];
|
||||
};
|
||||
|
||||
struct PBAudioAddr
|
||||
{
|
||||
u16 looping;
|
||||
u16 sample_format;
|
||||
u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is active)
|
||||
u16 loop_addr_lo;
|
||||
u16 end_addr_hi; // End of sample (and loop), inclusive
|
||||
u16 end_addr_lo;
|
||||
u16 cur_addr_hi;
|
||||
u16 cur_addr_lo;
|
||||
};
|
||||
|
||||
struct PBADPCMInfo
|
||||
{
|
||||
s16 coefs[16];
|
||||
u16 gain;
|
||||
u16 pred_scale;
|
||||
s16 yn1;
|
||||
s16 yn2;
|
||||
};
|
||||
|
||||
struct PBSampleRateConverter
|
||||
{
|
||||
// ratio = (f32)ratio * 0x10000;
|
||||
// valid range is 1/512 to 4.0000
|
||||
u16 ratio_hi; // integer part of sampling ratio
|
||||
u16 ratio_lo; // fraction part of sampling ratio
|
||||
u16 cur_addr_frac;
|
||||
u16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBSampleRateConverterWM
|
||||
{
|
||||
u16 currentAddressFrac;
|
||||
u16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBADPCMLoopInfo
|
||||
{
|
||||
u16 pred_scale;
|
||||
u16 yn1;
|
||||
u16 yn2;
|
||||
};
|
||||
|
||||
struct AXPB
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, ?, linear)
|
||||
u16 coef_select;
|
||||
u16 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixer mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdates updates;
|
||||
PBDpop dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBUnknown2 unknown3;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
u16 unknown_maybe_padding[3];
|
||||
};
|
||||
|
||||
struct PBLowPassFilter
|
||||
{
|
||||
u16 enabled;
|
||||
u16 yn1;
|
||||
u16 a0;
|
||||
u16 b0;
|
||||
};
|
||||
|
||||
struct PBBiquadFilter
|
||||
{
|
||||
|
||||
u16 on; // on = 2, off = 0
|
||||
u16 xn1; // History data
|
||||
u16 xn2;
|
||||
u16 yn1;
|
||||
u16 yn2;
|
||||
u16 b0; // Filter coefficients
|
||||
u16 b1;
|
||||
u16 b2;
|
||||
u16 a1;
|
||||
u16 a2;
|
||||
|
||||
};
|
||||
|
||||
union PBInfImpulseResponseWM
|
||||
{
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
};
|
||||
|
||||
struct AXPBWii
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u32 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[12]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// Seems like nintendo used an early version of AXWii and forgot to remove the update functionality ;p
|
||||
struct PBUpdatesWiiSports
|
||||
{
|
||||
u16 num_updates[3];
|
||||
u16 data_hi;
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
struct AXPBWiiSports
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u32 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdatesWiiSports updates;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[7]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// TODO: All these enums have changed a lot for wii
|
||||
enum {
|
||||
AUDIOFORMAT_ADPCM = 0,
|
||||
AUDIOFORMAT_PCM8 = 0x19,
|
||||
AUDIOFORMAT_PCM16 = 0xA,
|
||||
};
|
||||
|
||||
enum {
|
||||
SRCTYPE_LINEAR = 1,
|
||||
SRCTYPE_NEAREST = 2,
|
||||
MIXCONTROL_RAMPING = 8,
|
||||
};
|
||||
|
||||
// Both may be used at once
|
||||
enum {
|
||||
FILTER_LOWPASS = 1,
|
||||
FILTER_BIQUAD = 2,
|
||||
};
|
||||
|
||||
#endif // _UCODE_AX_STRUCTS_H
|
|
@ -1,271 +0,0 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AXWII_VOICE_H
|
||||
#define _UCODE_AXWII_VOICE_H
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXWii_ADPCM.h"
|
||||
#include "UCode_AX.h"
|
||||
#include "Mixer.h"
|
||||
#include "../../AudioInterface.h"
|
||||
|
||||
// MRAM -> ARAM for GC
|
||||
inline bool ReadPB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRAM -> ARAM for Wii
|
||||
inline bool ReadPB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
// preswap the mixer_control
|
||||
PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for GC
|
||||
inline bool WritePB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for Wii
|
||||
inline bool WritePB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
// preswap the mixer_control
|
||||
*(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: fix handling of gc/wii PB differences
|
||||
// TODO: generally fix up the mess - looks crazy and kinda wrong
|
||||
template<class ParamBlockType>
|
||||
inline void MixAddVoice(ParamBlockType &pb,
|
||||
int *templbuffer, int *temprbuffer,
|
||||
int _iSize)
|
||||
{
|
||||
if (pb.running)
|
||||
{
|
||||
const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo)
|
||||
* /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate()));
|
||||
u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
|
||||
u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
|
||||
|
||||
u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo;
|
||||
u32 frac = pb.src.cur_addr_frac;
|
||||
|
||||
// =======================================================================================
|
||||
// Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0
|
||||
// and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This
|
||||
// makes samplePos update in the correct way. I'm unsure how we are actually supposed to
|
||||
// detect that this setting. Updates did not fix this automatically.
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Stream settings
|
||||
// src_type = 2 (most other games have src_type = 0)
|
||||
// Affected games:
|
||||
// Baten Kaitos - Eternal Wings (2003)
|
||||
// Baten Kaitos - Origins (2006)?
|
||||
// Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps
|
||||
// the sound format plays in to, Baten use ADPCM, SC2 use PCM16
|
||||
//if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
{
|
||||
pb.src.ratio_hi = 1;
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Games that use looping to play non-looping music streams - SSBM has info in all
|
||||
// pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams
|
||||
// like any other looping streams the music works. I'm unsure how we are actually supposed to
|
||||
// detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may
|
||||
// identify these types of blocks. Updates did not write any looping values.
|
||||
if (
|
||||
(pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2)
|
||||
&& pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F
|
||||
)
|
||||
{
|
||||
pb.audio_addr.looping = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Top Spin 3 Wii
|
||||
if (pb.audio_addr.sample_format > 25)
|
||||
pb.audio_addr.sample_format = 0;
|
||||
|
||||
// =======================================================================================
|
||||
// Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to
|
||||
// compensate for that. _iSize can be as low as 100 or as high as 2000 some cases.
|
||||
for (int s = 0; s < _iSize; s++)
|
||||
{
|
||||
int sample = 0;
|
||||
u32 oldFrac = frac;
|
||||
frac += ratio;
|
||||
u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac
|
||||
|
||||
// =======================================================================================
|
||||
// Process sample format
|
||||
switch (pb.audio_addr.sample_format)
|
||||
{
|
||||
case AUDIOFORMAT_PCM8:
|
||||
pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample
|
||||
pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_PCM16:
|
||||
pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample
|
||||
pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_ADPCM:
|
||||
ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac);
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Overall volume control. In addition to this there is also separate volume settings to
|
||||
// different channels (left, right etc).
|
||||
frac &= 0xffff;
|
||||
|
||||
int vol = pb.vol_env.cur_volume >> 9;
|
||||
sample = sample * vol >> 8;
|
||||
|
||||
if (pb.mixer_control & MIXCONTROL_RAMPING)
|
||||
{
|
||||
int x = pb.vol_env.cur_volume;
|
||||
x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
|
||||
// that use this? Or how does it work?
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 0x7fff)
|
||||
x = 0x7fff;
|
||||
pb.vol_env.cur_volume = x; // maybe not per sample?? :P
|
||||
}
|
||||
|
||||
int leftmix = pb.mixer.left >> 5;
|
||||
int rightmix = pb.mixer.right >> 5;
|
||||
int left = sample * leftmix >> 8;
|
||||
int right = sample * rightmix >> 8;
|
||||
// adpcm has to walk from oldSamplePos to samplePos here
|
||||
templbuffer[s] += left;
|
||||
temprbuffer[s] += right;
|
||||
|
||||
// Control the behavior when we reach the end of the sample
|
||||
if (samplePos >= sampleEnd)
|
||||
{
|
||||
if (pb.audio_addr.looping == 1)
|
||||
{
|
||||
if ((samplePos & ~0x1f) == (sampleEnd & ~0x1f) || (pb.audio_addr.sample_format != AUDIOFORMAT_ADPCM))
|
||||
samplePos = loopPos;
|
||||
if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM))
|
||||
{
|
||||
pb.adpcm.yn1 = pb.adpcm_loop_info.yn1;
|
||||
pb.adpcm.yn2 = pb.adpcm_loop_info.yn2;
|
||||
pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pb.running = 0;
|
||||
samplePos = loopPos;
|
||||
//samplePos = samplePos - sampleEnd + loopPos;
|
||||
memset(&pb.dpop, 0, sizeof(pb.dpop));
|
||||
memset(pb.src.last_samples, 0, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end of the _iSize loop
|
||||
|
||||
// Update volume
|
||||
pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta);
|
||||
pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta);
|
||||
|
||||
pb.src.cur_addr_frac = (u16)frac;
|
||||
pb.audio_addr.cur_addr_hi = samplePos >> 16;
|
||||
pb.audio_addr.cur_addr_lo = (u16)samplePos;
|
||||
|
||||
} // if (pb.running)
|
||||
}
|
||||
|
||||
#endif
|
|
@ -27,13 +27,17 @@
|
|||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "../../DSP.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#ifdef AX_GC
|
||||
# define PB_TYPE AXPB
|
||||
# define MAX_SAMPLES_PER_FRAME 32
|
||||
#else
|
||||
# define PB_TYPE AXPBWii
|
||||
# define MAX_SAMPLES_PER_FRAME 96
|
||||
#endif
|
||||
|
||||
// Put all of that in an anonymous namespace to avoid stupid compilers merging
|
||||
|
@ -65,13 +69,22 @@ union AXBuffers
|
|||
int* auxC_left;
|
||||
int* auxC_right;
|
||||
int* auxC_surround;
|
||||
|
||||
int* wm_main0;
|
||||
int* wm_aux0;
|
||||
int* wm_main1;
|
||||
int* wm_aux1;
|
||||
int* wm_main2;
|
||||
int* wm_aux2;
|
||||
int* wm_main3;
|
||||
int* wm_aux3;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef AX_GC
|
||||
int* ptrs[9];
|
||||
#else
|
||||
int* ptrs[12];
|
||||
int* ptrs[20];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -127,6 +140,7 @@ void DumpPB(const PB_TYPE& pb)
|
|||
static u32 acc_loop_addr, acc_end_addr;
|
||||
static u32* acc_cur_addr;
|
||||
static PB_TYPE* acc_pb;
|
||||
static bool acc_end_reached;
|
||||
|
||||
// Sets up the simulated accelerator.
|
||||
void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
||||
|
@ -135,6 +149,7 @@ void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
|||
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
|
||||
acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr);
|
||||
acc_cur_addr = cur_addr;
|
||||
acc_end_reached = false;
|
||||
}
|
||||
|
||||
// Reads a sample from the simulated accelerator. Also handles looping and
|
||||
|
@ -144,6 +159,49 @@ u16 AcceleratorGetSample()
|
|||
{
|
||||
u16 ret;
|
||||
|
||||
// Have we reached the end address?
|
||||
//
|
||||
// On real hardware, this would raise an interrupt that is handled by the
|
||||
// UCode. We simulate what this interrupt does here.
|
||||
if ((*acc_cur_addr & ~1) == (acc_end_addr & ~1))
|
||||
{
|
||||
// loop back to loop_addr.
|
||||
*acc_cur_addr = acc_loop_addr;
|
||||
|
||||
if (acc_pb->audio_addr.looping)
|
||||
{
|
||||
// Set the ADPCM infos to continue processing at loop_addr.
|
||||
//
|
||||
// For some reason, yn1 and yn2 aren't set if the voice is not of
|
||||
// stream type. This is what the AX UCode does and I don't really
|
||||
// know why.
|
||||
acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale;
|
||||
if (!acc_pb->is_stream)
|
||||
{
|
||||
acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1;
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non looping voice reached the end -> running = 0.
|
||||
acc_pb->running = 0;
|
||||
|
||||
#ifdef AX_WII
|
||||
// One of the few meaningful differences between AXGC and AXWii:
|
||||
// while AXGC handles non looping voices ending by having 0000
|
||||
// samples at the loop address, AXWii has the 0000 samples
|
||||
// internally in DRAM and use an internal pointer to it (loop addr
|
||||
// does not contain 0000 samples on AXWii!).
|
||||
acc_end_reached = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// See above for explanations about acc_end_reached.
|
||||
if (acc_end_reached)
|
||||
return 0;
|
||||
|
||||
switch (acc_pb->audio_addr.sample_format)
|
||||
{
|
||||
case 0x00: // ADPCM
|
||||
|
@ -199,104 +257,159 @@ u16 AcceleratorGetSample()
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Have we reached the end address?
|
||||
//
|
||||
// On real hardware, this would raise an interrupt that is handled by the
|
||||
// UCode. We simulate what this interrupt does here.
|
||||
if ((*acc_cur_addr & ~1) == (acc_end_addr & ~1))
|
||||
{
|
||||
// loop back to loop_addr.
|
||||
*acc_cur_addr = acc_loop_addr;
|
||||
|
||||
if (acc_pb->audio_addr.looping)
|
||||
{
|
||||
// Set the ADPCM infos to continue processing at loop_addr.
|
||||
//
|
||||
// For some reason, yn1 and yn2 aren't set if the voice is not of
|
||||
// stream type. This is what the AX UCode does and I don't really
|
||||
// know why.
|
||||
acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale;
|
||||
if (!acc_pb->is_stream)
|
||||
{
|
||||
acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1;
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non looping voice reached the end -> running = 0.
|
||||
acc_pb->running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read 32 input samples from ARAM, decoding and converting rate if required.
|
||||
void GetInputSamples(PB_TYPE& pb, s16* samples)
|
||||
// Reads samples from the input callback, resamples them to <count> samples at
|
||||
// the wanted sample rate (computed from the ratio, see below).
|
||||
//
|
||||
// If srctype is SRCTYPE_POLYPHASE, coefficients need to be provided as well
|
||||
// (or the srctype will automatically be changed to LINEAR).
|
||||
//
|
||||
// Returns the current position after resampling (including fractional part).
|
||||
//
|
||||
// The input to output ratio is set in <ratio>, which is a floating point num
|
||||
// stored as a 32b integer:
|
||||
// * Upper 16 bits of the ratio are the integer part
|
||||
// * Lower 16 bits are the decimal part
|
||||
//
|
||||
// <curr_pos> is a 32b integer structured in the same way as the ratio: the
|
||||
// upper 16 bits are the integer part of the current position in the input
|
||||
// stream, and the lower 16 bits are the decimal part.
|
||||
//
|
||||
// We start getting samples not from sample 0, but 0.<curr_pos_frac>. This
|
||||
// avoids discontinuties in the audio stream, especially with very low ratios
|
||||
// which interpolate a lot of values between two "real" samples.
|
||||
u32 ResampleAudio(std::function<s16(u32)> input_callback, s16* output, u32 count,
|
||||
s16* last_samples, u32 curr_pos, u32 ratio, int srctype,
|
||||
const s16* coeffs)
|
||||
{
|
||||
int read_samples_count = 0;
|
||||
|
||||
// TODO(delroth): find out why the polyphase resampling algorithm causes
|
||||
// audio glitches in Wii games with non integral ratios.
|
||||
|
||||
// If DSP DROM coefficients are available, support polyphase resampling.
|
||||
if (0) // if (coeffs && srctype == SRCTYPE_POLYPHASE)
|
||||
{
|
||||
s16 temp[4];
|
||||
u32 idx = 0;
|
||||
|
||||
temp[idx++ & 3] = last_samples[0];
|
||||
temp[idx++ & 3] = last_samples[1];
|
||||
temp[idx++ & 3] = last_samples[2];
|
||||
temp[idx++ & 3] = last_samples[3];
|
||||
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
curr_pos += ratio;
|
||||
while (curr_pos >= 0x10000)
|
||||
{
|
||||
temp[idx++ & 3] = input_callback(read_samples_count++);
|
||||
curr_pos -= 0x10000;
|
||||
}
|
||||
|
||||
u16 curr_pos_frac = ((curr_pos & 0xFFFF) >> 9) << 2;
|
||||
const s16* c = &coeffs[curr_pos_frac];
|
||||
|
||||
s64 t0 = temp[idx++ & 3];
|
||||
s64 t1 = temp[idx++ & 3];
|
||||
s64 t2 = temp[idx++ & 3];
|
||||
s64 t3 = temp[idx++ & 3];
|
||||
|
||||
s64 samp = (t0 * c[0] + t1 * c[1] + t2 * c[2] + t3 * c[3]) >> 15;
|
||||
|
||||
output[i] = (s16)samp;
|
||||
}
|
||||
|
||||
last_samples[3] = temp[--idx & 3];
|
||||
last_samples[2] = temp[--idx & 3];
|
||||
last_samples[1] = temp[--idx & 3];
|
||||
last_samples[0] = temp[--idx & 3];
|
||||
}
|
||||
else if (srctype == SRCTYPE_LINEAR || srctype == SRCTYPE_POLYPHASE)
|
||||
{
|
||||
// This is the circular buffer containing samples to use for the
|
||||
// interpolation. It is initialized with the values from the PB, and it
|
||||
// will be stored back to the PB at the end.
|
||||
s16 temp[4];
|
||||
u32 idx = 0;
|
||||
|
||||
temp[idx++ & 3] = last_samples[0];
|
||||
temp[idx++ & 3] = last_samples[1];
|
||||
temp[idx++ & 3] = last_samples[2];
|
||||
temp[idx++ & 3] = last_samples[3];
|
||||
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
curr_pos += ratio;
|
||||
|
||||
// While our current position is >= 1.0, push new samples to the
|
||||
// circular buffer.
|
||||
while (curr_pos >= 0x10000)
|
||||
{
|
||||
temp[idx++ & 3] = input_callback(read_samples_count++);
|
||||
curr_pos -= 0x10000;
|
||||
}
|
||||
|
||||
// Get our current fractional position, used to know how much of
|
||||
// curr0 and how much of curr1 the output sample should be.
|
||||
u16 curr_frac = curr_pos & 0xFFFF;
|
||||
u16 inv_curr_frac = -curr_frac;
|
||||
|
||||
// Interpolate! If curr_frac is 0, we can simply take the last
|
||||
// sample without any multiplying.
|
||||
s16 sample;
|
||||
if (curr_frac)
|
||||
{
|
||||
s32 s0 = temp[idx++ & 3];
|
||||
s32 s1 = temp[idx++ & 3];
|
||||
|
||||
sample = ((s0 * inv_curr_frac) + (s1 * curr_frac)) >> 16;
|
||||
idx += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sample = temp[idx++ & 3];
|
||||
idx += 3;
|
||||
}
|
||||
|
||||
output[i] = sample;
|
||||
}
|
||||
|
||||
// Update the four last_samples values.
|
||||
last_samples[3] = temp[--idx & 3];
|
||||
last_samples[2] = temp[--idx & 3];
|
||||
last_samples[1] = temp[--idx & 3];
|
||||
last_samples[0] = temp[--idx & 3];
|
||||
}
|
||||
else // SRCTYPE_NEAREST
|
||||
{
|
||||
// No sample rate conversion here: simply read samples from the
|
||||
// accelerator to the output buffer.
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
output[i] = input_callback(i);
|
||||
|
||||
memcpy(last_samples, output + count - 4, 4 * sizeof (u16));
|
||||
}
|
||||
|
||||
return curr_pos;
|
||||
}
|
||||
|
||||
// Read <count> input samples from ARAM, decoding and converting rate
|
||||
// if required.
|
||||
void GetInputSamples(PB_TYPE& pb, s16* samples, u16 count, const s16* coeffs)
|
||||
{
|
||||
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
|
||||
AcceleratorSetup(&pb, &cur_addr);
|
||||
|
||||
// TODO: support polyphase interpolation if coefficients are available.
|
||||
if (pb.src_type == SRCTYPE_POLYPHASE || pb.src_type == SRCTYPE_LINEAR)
|
||||
{
|
||||
// Convert the input to a higher or lower sample rate using a linear
|
||||
// interpolation algorithm. The input to output ratio is set in
|
||||
// pb.src.ratio, which is a floating point num stored as a 32b integer:
|
||||
// * Upper 16 bits of the ratio are the integer part
|
||||
// * Lower 16 bits are the decimal part
|
||||
u32 ratio = HILO_TO_32(pb.src.ratio);
|
||||
|
||||
// We start getting samples not from sample 0, but 0.<cur_addr_frac>.
|
||||
// This avoids discontinuties in the audio stream, especially with very
|
||||
// low ratios which interpolate a lot of values between two "real"
|
||||
// samples.
|
||||
u32 curr_pos = pb.src.cur_addr_frac;
|
||||
|
||||
// These are the two samples between which we interpolate. The initial
|
||||
// values are stored in the PB, and we update them when resampling the
|
||||
// input data.
|
||||
s16 curr0 = pb.src.last_samples[2];
|
||||
s16 curr1 = pb.src.last_samples[3];
|
||||
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
// Get our current fractional position, used to know how much of
|
||||
// curr0 and how much of curr1 the output sample should be.
|
||||
s32 curr_frac_pos = curr_pos & 0xFFFF;
|
||||
|
||||
// Linear interpolation: s1 + (s2 - s1) * pos
|
||||
s16 sample = curr0 + (s16)(((curr1 - curr0) * (s32)curr_frac_pos) >> 16);
|
||||
samples[i] = sample;
|
||||
|
||||
curr_pos += ratio;
|
||||
|
||||
// While our current position is >= 1.0, shift to the next 2
|
||||
// samples for interpolation.
|
||||
while ((curr_pos >> 16) != 0)
|
||||
{
|
||||
curr0 = curr1;
|
||||
curr1 = AcceleratorGetSample();
|
||||
curr_pos -= 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the two last_samples values in the PB as well as the current
|
||||
// position.
|
||||
pb.src.last_samples[2] = curr0;
|
||||
pb.src.last_samples[3] = curr1;
|
||||
pb.src.cur_addr_frac = curr_pos & 0xFFFF;
|
||||
}
|
||||
else // SRCTYPE_NEAREST
|
||||
{
|
||||
// No sample rate conversion here: simply read 32 samples from the
|
||||
// accelerator to the output buffer.
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
samples[i] = AcceleratorGetSample();
|
||||
|
||||
memcpy(pb.src.last_samples, samples + 28, 4 * sizeof (u16));
|
||||
}
|
||||
if (coeffs)
|
||||
coeffs += pb.coef_select * 0x200;
|
||||
u32 curr_pos = ResampleAudio([](u32) { return AcceleratorGetSample(); },
|
||||
samples, count, pb.src.last_samples,
|
||||
pb.src.cur_addr_frac, HILO_TO_32(pb.src.ratio),
|
||||
pb.src_type, coeffs);
|
||||
pb.src.cur_addr_frac = (curr_pos & 0xFFFF);
|
||||
|
||||
// Update current position in the PB.
|
||||
pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16);
|
||||
|
@ -304,7 +417,7 @@ void GetInputSamples(PB_TYPE& pb, s16* samples)
|
|||
}
|
||||
|
||||
// Add samples to an output buffer, with optional volume ramping.
|
||||
void MixAdd(int* out, const s16* input, u16* pvol, s16* dpop, bool ramp)
|
||||
void MixAdd(int* out, const s16* input, u32 count, u16* pvol, s16* dpop, bool ramp)
|
||||
{
|
||||
u16& volume = pvol[0];
|
||||
u16 volume_delta = pvol[1];
|
||||
|
@ -315,7 +428,7 @@ void MixAdd(int* out, const s16* input, u16* pvol, s16* dpop, bool ramp)
|
|||
if (!ramp)
|
||||
volume_delta = 0;
|
||||
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
s64 sample = input[i];
|
||||
sample *= volume;
|
||||
|
@ -328,62 +441,69 @@ void MixAdd(int* out, const s16* input, u16* pvol, s16* dpop, bool ramp)
|
|||
}
|
||||
}
|
||||
|
||||
// Process 1ms of audio (32 samples) from a PB and mix it to the buffers.
|
||||
void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
||||
// Execute a low pass filter on the samples using one history value. Returns
|
||||
// the new history value.
|
||||
s16 LowPassFilter(s16* samples, u32 count, s16 yn1, u16 a0, u16 b0)
|
||||
{
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
yn1 = samples[i] = (a0 * (s32)samples[i] + b0 * (s32)yn1) >> 15;
|
||||
return yn1;
|
||||
}
|
||||
|
||||
// Process 1ms of audio (for AX GC) or 3ms of audio (for AX Wii) from a PB and
|
||||
// mix it to the output buffers.
|
||||
void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl mctrl, const s16* coeffs)
|
||||
{
|
||||
// If the voice is not running, nothing to do.
|
||||
if (!pb.running)
|
||||
return;
|
||||
|
||||
// Read input samples, performing sample rate conversion if needed.
|
||||
s16 samples[32];
|
||||
GetInputSamples(pb, samples);
|
||||
s16 samples[MAX_SAMPLES_PER_FRAME];
|
||||
GetInputSamples(pb, samples, count, coeffs);
|
||||
|
||||
// Apply a global volume ramp using the volume envelope parameters.
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
s64 sample = 2 * (s16)samples[i] * (s16)pb.vol_env.cur_volume;
|
||||
samples[i] = (s16)(sample >> 16);
|
||||
samples[i] = ((s32)samples[i] * pb.vol_env.cur_volume) >> 15;
|
||||
pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta;
|
||||
}
|
||||
|
||||
// Optionally, execute a low pass filter
|
||||
if (pb.lpf.enabled)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
pb.lpf.yn1 = LowPassFilter(samples, count, pb.lpf.yn1, pb.lpf.a0, pb.lpf.b0);
|
||||
|
||||
// Mix LRS, AUXA and AUXB depending on mixer_control
|
||||
// TODO: Handle DPL2 on AUXB.
|
||||
|
||||
if (mctrl & MIX_L)
|
||||
MixAdd(buffers.left, samples, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
||||
MixAdd(buffers.left, samples, count, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
||||
if (mctrl & MIX_R)
|
||||
MixAdd(buffers.right, samples, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
||||
MixAdd(buffers.right, samples, count, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
||||
if (mctrl & MIX_S)
|
||||
MixAdd(buffers.surround, samples, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
||||
MixAdd(buffers.surround, samples, count, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
||||
|
||||
if (mctrl & MIX_AUXA_L)
|
||||
MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||
MixAdd(buffers.auxA_left, samples, count, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||
if (mctrl & MIX_AUXA_R)
|
||||
MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||
MixAdd(buffers.auxA_right, samples, count, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||
if (mctrl & MIX_AUXA_S)
|
||||
MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||
MixAdd(buffers.auxA_surround, samples, count, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||
|
||||
if (mctrl & MIX_AUXB_L)
|
||||
MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||
MixAdd(buffers.auxB_left, samples, count, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||
if (mctrl & MIX_AUXB_R)
|
||||
MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||
MixAdd(buffers.auxB_right, samples, count, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||
if (mctrl & MIX_AUXB_S)
|
||||
MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||
MixAdd(buffers.auxB_surround, samples, count, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||
|
||||
#ifdef AX_WII
|
||||
if (mctrl & MIX_AUXC_L)
|
||||
MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||
MixAdd(buffers.auxC_left, samples, count, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||
if (mctrl & MIX_AUXC_R)
|
||||
MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||
MixAdd(buffers.auxC_right, samples, count, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||
if (mctrl & MIX_AUXC_S)
|
||||
MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||
MixAdd(buffers.auxC_surround, samples, count, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||
#endif
|
||||
|
||||
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||
|
@ -391,6 +511,47 @@ void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
|||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
#ifdef AX_WII
|
||||
// Wiimote mixing.
|
||||
if (pb.remote)
|
||||
{
|
||||
// Old AXWii versions process ms per ms.
|
||||
u16 wm_count = count == 96 ? 18 : 6;
|
||||
|
||||
// Interpolate at most 18 samples from the 96 samples we read before.
|
||||
s16 wm_samples[18];
|
||||
|
||||
// We use ratio 0x55555 == (5 * 65536 + 21845) / 65536 == 5.3333 which
|
||||
// is the nearest we can get to 96/18
|
||||
u32 curr_pos = ResampleAudio([&samples](u32 i) { return samples[i]; },
|
||||
wm_samples, wm_count, pb.remote_src.last_samples,
|
||||
pb.remote_src.cur_addr_frac, 0x55555,
|
||||
SRCTYPE_POLYPHASE, coeffs);
|
||||
pb.remote_src.cur_addr_frac = curr_pos & 0xFFFF;
|
||||
|
||||
// Mix to main[0-3] and aux[0-3]
|
||||
#define WMCHAN_MIX_ON(n) ((pb.remote_mixer_control >> (2 * n)) & 3)
|
||||
#define WMCHAN_MIX_RAMP(n) ((pb.remote_mixer_control >> (2 * n)) & 2)
|
||||
|
||||
if (WMCHAN_MIX_ON(0))
|
||||
MixAdd(buffers.wm_main0, wm_samples, wm_count, &pb.remote_mixer.main0, &pb.remote_dpop.main0, WMCHAN_MIX_RAMP(0));
|
||||
if (WMCHAN_MIX_ON(1))
|
||||
MixAdd(buffers.wm_aux0, wm_samples, wm_count, &pb.remote_mixer.aux0, &pb.remote_dpop.aux0, WMCHAN_MIX_RAMP(1));
|
||||
if (WMCHAN_MIX_ON(2))
|
||||
MixAdd(buffers.wm_main1, wm_samples, wm_count, &pb.remote_mixer.main1, &pb.remote_dpop.main1, WMCHAN_MIX_RAMP(2));
|
||||
if (WMCHAN_MIX_ON(3))
|
||||
MixAdd(buffers.wm_aux1, wm_samples, wm_count, &pb.remote_mixer.aux1, &pb.remote_dpop.aux1, WMCHAN_MIX_RAMP(3));
|
||||
if (WMCHAN_MIX_ON(4))
|
||||
MixAdd(buffers.wm_main2, wm_samples, wm_count, &pb.remote_mixer.main2, &pb.remote_dpop.main2, WMCHAN_MIX_RAMP(4));
|
||||
if (WMCHAN_MIX_ON(5))
|
||||
MixAdd(buffers.wm_aux2, wm_samples, wm_count, &pb.remote_mixer.aux2, &pb.remote_dpop.aux2, WMCHAN_MIX_RAMP(5));
|
||||
if (WMCHAN_MIX_ON(6))
|
||||
MixAdd(buffers.wm_main3, wm_samples, wm_count, &pb.remote_mixer.main3, &pb.remote_dpop.main3, WMCHAN_MIX_RAMP(6));
|
||||
if (WMCHAN_MIX_ON(7))
|
||||
MixAdd(buffers.wm_aux3, wm_samples, wm_count, &pb.remote_mixer.aux3, &pb.remote_dpop.aux3, WMCHAN_MIX_RAMP(7));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -48,11 +48,11 @@ void CUCode_CARD::HandleMail(u32 _uMail)
|
|||
{
|
||||
if (_uMail == 0xFF000000) // unlock card
|
||||
{
|
||||
// m_Mails.push(0x00000001); // ACK (actualy anything != 0)
|
||||
// m_Mails.push(0x00000001); // ACK (actually anything != 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "CUCode_CARD - unknown cmd: %x", _uMail);
|
||||
DEBUG_LOG(DSPHLE, "CUCode_CARD - unknown command: %x", _uMail);
|
||||
}
|
||||
|
||||
m_rMailHandler.PushMail(DSP_DONE);
|
||||
|
|
|
@ -122,8 +122,8 @@ void CUCode_GBA::HandleMail(u32 _uMail)
|
|||
*(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23);
|
||||
|
||||
// Done!
|
||||
DEBUG_LOG(DSPHLE, "\n%08x -> key %08x len %08x dest_addr %08x unk1 %08x unk2 %08x"
|
||||
" 22 %04x 23 %04x",
|
||||
DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x"
|
||||
" 22: %04x, 23: %04x",
|
||||
mramaddr,
|
||||
*(u32*)sec_params.key, sec_params.length, sec_params.dest_addr,
|
||||
*(u32*)sec_params.unk1, *(u32*)sec_params.unk2,
|
||||
|
@ -143,12 +143,12 @@ void CUCode_GBA::HandleMail(u32 _uMail)
|
|||
m_DSPHLE->SetUCode(UCODE_ROM);
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG(DSPHLE, "CUCode_GBA - unknown 0xcdd1 cmd: %08x", _uMail);
|
||||
DEBUG_LOG(DSPHLE, "CUCode_GBA - unknown 0xcdd1 command: %08x", _uMail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "CUCode_GBA - unknown cmd: %08x", _uMail);
|
||||
DEBUG_LOG(DSPHLE, "CUCode_GBA - unknown command: %08x", _uMail);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,383 +0,0 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include "../MailHandler.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "UCode_NewAXWii.h"
|
||||
|
||||
#define AX_WII
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
|
||||
CUCode_NewAXWii::CUCode_NewAXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
: CUCode_AX(dsp_hle, l_CRC)
|
||||
{
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_NewAXWii");
|
||||
}
|
||||
|
||||
CUCode_NewAXWii::~CUCode_NewAXWii()
|
||||
{
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::HandleCommandList()
|
||||
{
|
||||
// Temp variables for addresses computation
|
||||
u16 addr_hi, addr_lo;
|
||||
u16 addr2_hi, addr2_lo;
|
||||
u16 volume;
|
||||
|
||||
// WARN_LOG(DSPHLE, "Command list:");
|
||||
// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
|
||||
// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
|
||||
// WARN_LOG(DSPHLE, "-------------");
|
||||
|
||||
u32 curr_idx = 0;
|
||||
bool end = false;
|
||||
while (!end)
|
||||
{
|
||||
u16 cmd = m_cmdlist[curr_idx++];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
// Some of these commands are unknown, or unused in this AX HLE.
|
||||
// We still need to skip their arguments using "curr_idx += N".
|
||||
|
||||
case CMD_SETUP:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetupProcessing(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_UNK_01: curr_idx += 2; break;
|
||||
case CMD_UNK_02: curr_idx += 2; break;
|
||||
case CMD_UNK_03: curr_idx += 2; break;
|
||||
|
||||
case CMD_PROCESS:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
ProcessPBList(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_MIX_AUXA:
|
||||
case CMD_MIX_AUXB:
|
||||
case CMD_MIX_AUXC:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume);
|
||||
break;
|
||||
|
||||
// These two go together and manipulate some AUX buffers.
|
||||
case CMD_UNK_08: curr_idx += 13; break;
|
||||
case CMD_UNK_09: curr_idx += 13; break;
|
||||
|
||||
case CMD_UNK_0A: curr_idx += 4; break;
|
||||
|
||||
case CMD_OUTPUT:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume);
|
||||
break;
|
||||
|
||||
case CMD_UNK_0C: curr_idx += 5; break;
|
||||
|
||||
case CMD_WM_OUTPUT:
|
||||
{
|
||||
u32 addresses[4] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
};
|
||||
curr_idx += 8;
|
||||
OutputWMSamples(addresses);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_END:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::SetupProcessing(u32 init_addr)
|
||||
{
|
||||
// TODO: should be easily factorizable with AX
|
||||
s16 init_data[60];
|
||||
|
||||
for (u32 i = 0; i < 60; ++i)
|
||||
init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
|
||||
|
||||
// List of all buffers we have to initialize
|
||||
struct {
|
||||
int* ptr;
|
||||
u32 samples;
|
||||
} buffers[] = {
|
||||
{ m_samples_left, 32 },
|
||||
{ m_samples_right, 32 },
|
||||
{ m_samples_surround, 32 },
|
||||
{ m_samples_auxA_left, 32 },
|
||||
{ m_samples_auxA_right, 32 },
|
||||
{ m_samples_auxA_surround, 32 },
|
||||
{ m_samples_auxB_left, 32 },
|
||||
{ m_samples_auxB_right, 32 },
|
||||
{ m_samples_auxB_surround, 32 },
|
||||
{ m_samples_auxC_left, 32 },
|
||||
{ m_samples_auxC_right, 32 },
|
||||
{ m_samples_auxC_surround, 32 },
|
||||
|
||||
{ m_samples_wm0, 6 },
|
||||
{ m_samples_aux0, 6 },
|
||||
{ m_samples_wm1, 6 },
|
||||
{ m_samples_aux1, 6 },
|
||||
{ m_samples_wm2, 6 },
|
||||
{ m_samples_aux2, 6 },
|
||||
{ m_samples_wm3, 6 },
|
||||
{ m_samples_aux3, 6 }
|
||||
};
|
||||
|
||||
u32 init_idx = 0;
|
||||
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
|
||||
{
|
||||
s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
|
||||
s16 delta = (s16)init_data[init_idx + 2];
|
||||
|
||||
init_idx += 3;
|
||||
|
||||
if (!init_val)
|
||||
memset(buffers[i].ptr, 0, 3 * buffers[i].samples * sizeof (int));
|
||||
else
|
||||
{
|
||||
for (u32 j = 0; j < 3 * buffers[i].samples; ++j)
|
||||
{
|
||||
buffers[i].ptr[j] = init_val;
|
||||
init_val += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AXMixControl CUCode_NewAXWii::ConvertMixerControl(u32 mixer_control)
|
||||
{
|
||||
u32 ret = 0;
|
||||
|
||||
if (mixer_control & 0x00000001) ret |= MIX_L;
|
||||
if (mixer_control & 0x00000002) ret |= MIX_R;
|
||||
if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
|
||||
if (mixer_control & 0x00000008) ret |= MIX_S;
|
||||
if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
|
||||
if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
|
||||
if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
|
||||
if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
|
||||
if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
|
||||
if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
|
||||
if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
|
||||
if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
|
||||
if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
|
||||
if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
|
||||
if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
|
||||
if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
|
||||
if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
|
||||
if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
|
||||
if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
|
||||
if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
|
||||
|
||||
return (AXMixControl)ret;
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::ProcessPBList(u32 pb_addr)
|
||||
{
|
||||
const u32 spms = 32;
|
||||
|
||||
AXPBWii pb;
|
||||
|
||||
while (pb_addr)
|
||||
{
|
||||
AXBuffers buffers = {{
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround,
|
||||
m_samples_auxA_left,
|
||||
m_samples_auxA_right,
|
||||
m_samples_auxA_surround,
|
||||
m_samples_auxB_left,
|
||||
m_samples_auxB_right,
|
||||
m_samples_auxB_surround,
|
||||
m_samples_auxC_left,
|
||||
m_samples_auxC_right,
|
||||
m_samples_auxC_surround
|
||||
}};
|
||||
|
||||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
|
||||
{
|
||||
Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)));
|
||||
|
||||
// Forward the buffers
|
||||
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||
buffers.ptrs[i] += spms;
|
||||
}
|
||||
|
||||
WritePB(pb_addr, pb);
|
||||
pb_addr = HILO_TO_32(pb.next_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume)
|
||||
{
|
||||
int* buffers[3] = { 0 };
|
||||
int* main_buffers[3] = {
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround
|
||||
};
|
||||
|
||||
switch (aux_id)
|
||||
{
|
||||
case 0:
|
||||
buffers[0] = m_samples_auxA_left;
|
||||
buffers[1] = m_samples_auxA_right;
|
||||
buffers[2] = m_samples_auxA_surround;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffers[0] = m_samples_auxB_left;
|
||||
buffers[1] = m_samples_auxB_right;
|
||||
buffers[2] = m_samples_auxB_surround;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffers[0] = m_samples_auxC_left;
|
||||
buffers[1] = m_samples_auxC_right;
|
||||
buffers[2] = m_samples_auxC_surround;
|
||||
break;
|
||||
}
|
||||
|
||||
// Send the content of AUX buffers to the CPU
|
||||
if (write_addr)
|
||||
{
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
*ptr++ = Common::swap32(buffers[i][j]);
|
||||
}
|
||||
|
||||
// Then read the buffers from the CPU and add to our main buffers.
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
{
|
||||
s64 new_val = main_buffers[i][j] + Common::swap32(*ptr++);
|
||||
main_buffers[i][j] = (new_val * volume) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume)
|
||||
{
|
||||
int surround_buffer[3 * 32] = { 0 };
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
surround_buffer[i] = Common::swap32(m_samples_surround[i]);
|
||||
memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
|
||||
|
||||
short buffer[3 * 32 * 2];
|
||||
|
||||
// Clamp internal buffers to 16 bits.
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
int left = m_samples_left[i];
|
||||
int right = m_samples_right[i];
|
||||
|
||||
// Apply global volume. Cast to s64 to avoid overflow.
|
||||
left = ((s64)left * volume) >> 15;
|
||||
right = ((s64)right * volume) >> 15;
|
||||
|
||||
if (left < -32767) left = -32767;
|
||||
if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
if (right > 32767) right = 32767;
|
||||
|
||||
m_samples_left[i] = left;
|
||||
m_samples_right[i] = right;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
buffer[2 * i] = Common::swap16(m_samples_left[i]);
|
||||
buffer[2 * i + 1] = Common::swap16(m_samples_right[i]);
|
||||
}
|
||||
|
||||
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::OutputWMSamples(u32* addresses)
|
||||
{
|
||||
int* buffers[] = {
|
||||
m_samples_wm0,
|
||||
m_samples_wm1,
|
||||
m_samples_wm2,
|
||||
m_samples_wm3
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
{
|
||||
int* in = buffers[i];
|
||||
u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
|
||||
for (u32 j = 0; j < 3 * 6; ++j)
|
||||
{
|
||||
int sample = in[j];
|
||||
if (sample < -32767) sample = -32767;
|
||||
if (sample > 32767) sample = 32767;
|
||||
out[j] = Common::swap16((u16)sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_processing);
|
||||
|
||||
DoStateShared(p);
|
||||
DoAXState(p);
|
||||
|
||||
p.Do(m_samples_auxC_left);
|
||||
p.Do(m_samples_auxC_right);
|
||||
p.Do(m_samples_auxC_surround);
|
||||
|
||||
p.Do(m_samples_wm0);
|
||||
p.Do(m_samples_wm1);
|
||||
p.Do(m_samples_wm2);
|
||||
p.Do(m_samples_wm3);
|
||||
|
||||
p.Do(m_samples_aux0);
|
||||
p.Do(m_samples_aux1);
|
||||
p.Do(m_samples_aux2);
|
||||
p.Do(m_samples_aux3);
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_NEWAXWII_H
|
||||
#define _UCODE_NEWAXWII_H
|
||||
|
||||
#include "UCode_AX.h"
|
||||
|
||||
class CUCode_NewAXWii : public CUCode_AX
|
||||
{
|
||||
public:
|
||||
CUCode_NewAXWii(DSPHLE *dsp_hle, u32 _CRC);
|
||||
virtual ~CUCode_NewAXWii();
|
||||
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
protected:
|
||||
int m_samples_auxC_left[32 * 3];
|
||||
int m_samples_auxC_right[32 * 3];
|
||||
int m_samples_auxC_surround[32 * 3];
|
||||
|
||||
// Wiimote buffers
|
||||
int m_samples_wm0[6 * 3];
|
||||
int m_samples_aux0[6 * 3];
|
||||
int m_samples_wm1[6 * 3];
|
||||
int m_samples_aux1[6 * 3];
|
||||
int m_samples_wm2[6 * 3];
|
||||
int m_samples_aux2[6 * 3];
|
||||
int m_samples_wm3[6 * 3];
|
||||
int m_samples_aux3[6 * 3];
|
||||
|
||||
// Convert a mixer_control bitfield to our internal representation for that
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume);
|
||||
void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume);
|
||||
void OutputWMSamples(u32* addresses); // 4 addresses
|
||||
|
||||
private:
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_UNK_01 = 0x01,
|
||||
CMD_UNK_02 = 0x02,
|
||||
CMD_UNK_03 = 0x03,
|
||||
CMD_PROCESS = 0x04,
|
||||
CMD_MIX_AUXA = 0x05,
|
||||
CMD_MIX_AUXB = 0x06,
|
||||
CMD_MIX_AUXC = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_UNK_09 = 0x09,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_OUTPUT = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_WM_OUTPUT = 0x0D,
|
||||
CMD_END = 0x0E
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _UCODE_AXWII
|
|
@ -112,7 +112,7 @@ u8 *CUCode_Zelda::GetARAMPointer(u32 address)
|
|||
|
||||
void CUCode_Zelda::Update(int cycles)
|
||||
{
|
||||
if (!IsLightVersion())
|
||||
if (!IsLightVersion())
|
||||
{
|
||||
if (m_rMailHandler.GetNextMail() == DSP_FRAME_END)
|
||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
|
@ -445,7 +445,7 @@ void CUCode_Zelda::ExecuteList()
|
|||
Sync = CmdMail >> 16;
|
||||
|
||||
DEBUG_LOG(DSPHLE, "==============================================================================");
|
||||
DEBUG_LOG(DSPHLE, "Zelda UCode - execute dlist (cmd: 0x%04x : sync: 0x%04x)", Command, Sync);
|
||||
DEBUG_LOG(DSPHLE, "Zelda UCode - execute dlist (command: 0x%04x : sync: 0x%04x)", Command, Sync);
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
|
@ -545,7 +545,7 @@ void CUCode_Zelda::ExecuteList()
|
|||
|
||||
// default ... zelda ww jumps to 0x0043
|
||||
default:
|
||||
PanicAlert("Zelda UCode - unknown cmd: %x (size %i)", Command, m_numSteps);
|
||||
PanicAlert("Zelda UCode - unknown command: %x (size %i)", Command, m_numSteps);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -218,7 +218,6 @@ private:
|
|||
s32* m_LeftBuffer;
|
||||
s32* m_RightBuffer;
|
||||
|
||||
|
||||
// If you add variables, remember to keep DoState() and the constructor up to date.
|
||||
|
||||
s16 m_AFCCoefTable[32];
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "UCode_AX.h"
|
||||
#include "UCode_AXWii.h"
|
||||
#include "UCode_NewAXWii.h"
|
||||
#include "UCode_Zelda.h"
|
||||
#include "UCode_ROM.h"
|
||||
#include "UCode_CARD.h"
|
||||
|
@ -27,12 +26,6 @@
|
|||
#include "UCode_GBA.h"
|
||||
#include "Hash.h"
|
||||
|
||||
#if 0
|
||||
# define AXWII CUCode_NewAXWii
|
||||
#else
|
||||
# define AXWII CUCode_AXWii
|
||||
#endif
|
||||
|
||||
IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
|
||||
{
|
||||
switch (_CRC)
|
||||
|
@ -97,13 +90,13 @@ IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
|
|||
case 0x4cc52064: // Bleach: Versus Crusade
|
||||
case 0xd9c4bf34: // WiiMenu
|
||||
INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", _CRC);
|
||||
return new AXWII(dsp_hle, _CRC);
|
||||
return new CUCode_AXWii(dsp_hle, _CRC);
|
||||
|
||||
default:
|
||||
if (bWii)
|
||||
{
|
||||
PanicAlert("DSPHLE: Unknown ucode (CRC = %08x) - forcing AXWii.\n\nTry LLE emulator if this is homebrew.", _CRC);
|
||||
return new AXWII(dsp_hle, _CRC);
|
||||
return new CUCode_AXWii(dsp_hle, _CRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -270,7 +270,7 @@ void DSPLLE::DSP_WriteMailBoxHigh(bool _CPUMailbox, u16 _uHighMail)
|
|||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(DSPLLE, "CPU cant write to DSP mailbox");
|
||||
ERROR_LOG(DSPLLE, "CPU can't write to DSP mailbox");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,7 +282,7 @@ void DSPLLE::DSP_WriteMailBoxLow(bool _CPUMailbox, u16 _uLowMail)
|
|||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(DSPLLE, "CPU cant write to DSP mailbox");
|
||||
ERROR_LOG(DSPLLE, "CPU can't write to DSP mailbox");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc)
|
|||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Cant open file (%s) to dump UCode!!", binFile);
|
||||
PanicAlert("Can't open file (%s) to dump UCode!!", binFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ void AutoDisassembly(u16 start_addr, u16 end_addr)
|
|||
break;
|
||||
}
|
||||
|
||||
//NOTICE_LOG(DSPLLE, "added %04x %i %s", addr, line_counter, buf.c_str());
|
||||
//NOTICE_LOG(DSPLLE, "Added %04x %i %s", addr, line_counter, buf.c_str());
|
||||
lines.push_back(buf);
|
||||
line_counter++;
|
||||
}
|
||||
|
|
|
@ -671,7 +671,7 @@ void ExecuteCommand(UDICR& _DICR)
|
|||
// Here is the actual Disk Reading
|
||||
if (!DVDRead(iDVDOffset, m_DIMAR.Address, m_DILENGTH.Length))
|
||||
{
|
||||
PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
PanicAlertT("Can't read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -681,7 +681,7 @@ void ExecuteCommand(UDICR& _DICR)
|
|||
_dbg_assert_(DVDINTERFACE, m_DICMDBUF[2].Hex == m_DILENGTH.Length);
|
||||
_dbg_assert_(DVDINTERFACE, m_DILENGTH.Length == 0x20);
|
||||
if (!DVDRead(m_DICMDBUF[1].Hex, m_DIMAR.Address, m_DILENGTH.Length))
|
||||
PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
PanicAlertT("Can't read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
WARN_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(m_DIMAR.Address));
|
||||
break;
|
||||
|
||||
|
@ -712,7 +712,7 @@ void ExecuteCommand(UDICR& _DICR)
|
|||
/*
|
||||
if (iDVDOffset == 0x84800000)
|
||||
{
|
||||
ERROR_LOG(DVDINTERFACE, "firmware upload");
|
||||
ERROR_LOG(DVDINTERFACE, "Firmware upload");
|
||||
}
|
||||
else*/
|
||||
if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40)
|
||||
|
|
|
@ -180,13 +180,13 @@ void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
|||
_uReturnValue = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "(r32) 0x%08x channel: %i reg: %s",
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "(r32) 0x%08x channel: %i register: %s",
|
||||
_uReturnValue, m_ChannelId, Debug_GetRegisterName(_iRegister));
|
||||
}
|
||||
|
||||
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
||||
{
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "(w32) 0x%08x channel: %i reg: %s",
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "(w32) 0x%08x channel: %i register: %s",
|
||||
_iValue, m_ChannelId, Debug_GetRegisterName(_iRegister));
|
||||
|
||||
switch (_iRegister)
|
||||
|
@ -222,17 +222,17 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
|||
break;
|
||||
|
||||
case EXI_DMAADDR:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, channel %i", m_ChannelId);
|
||||
m_DMAMemoryAddress = _iValue;
|
||||
break;
|
||||
|
||||
case EXI_DMALENGTH:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, channel %i", m_ChannelId);
|
||||
m_DMALength = _iValue;
|
||||
break;
|
||||
|
||||
case EXI_DMACONTROL:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, channel %i", m_ChannelId);
|
||||
m_Control.Hex = _iValue;
|
||||
|
||||
if (m_Control.TSTART)
|
||||
|
@ -274,7 +274,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
|||
break;
|
||||
|
||||
case EXI_IMMDATA:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, channel %i", m_ChannelId);
|
||||
m_ImmData = _iValue;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ void CEXIAMBaseboard::TransferByte(u8& _byte)
|
|||
_byte = m_have_irq ? 0xFF : 0;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(SP1, 0, "Unknown AM-BB cmd");
|
||||
_dbg_assert_msg_(SP1, 0, "Unknown AM-BB command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ CEXIETHERNET::CEXIETHERNET()
|
|||
memcpy(&mBbaMem[BBA_NAFR_PAR0], mac_addr, 6);
|
||||
}
|
||||
|
||||
// hax .. fully established 100BASE-T link
|
||||
// HACK: .. fully established 100BASE-T link
|
||||
mBbaMem[BBA_NWAYS] = NWAYS_LS100 | NWAYS_LPNWAY | NWAYS_100TXF | NWAYS_ANCLPT;
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
@ -175,7 +175,7 @@ void CEXIETHERNET::ImmWrite(u32 data, u32 size)
|
|||
|
||||
if (transfer.address == BBA_IOB && transfer.region == transfer.MX)
|
||||
{
|
||||
ERROR_LOG(SP1, "Usage of BBA_IOB indicates that the rx packet descriptor has been corrupted, killing dolphin...");
|
||||
ERROR_LOG(SP1, "Usage of BBA_IOB indicates that the rx packet descriptor has been corrupted. Killing Dolphin...");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -248,7 +248,7 @@ u32 CEXIETHERNET::ImmRead(u32 size)
|
|||
|
||||
void CEXIETHERNET::DMAWrite(u32 addr, u32 size)
|
||||
{
|
||||
DEBUG_LOG(SP1, "dma w: %08x %x", addr, size);
|
||||
DEBUG_LOG(SP1, "DMA write: %08x %x", addr, size);
|
||||
|
||||
if (transfer.region == transfer.MX &&
|
||||
transfer.direction == transfer.WRITE &&
|
||||
|
@ -258,7 +258,7 @@ void CEXIETHERNET::DMAWrite(u32 addr, u32 size)
|
|||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(SP1, "dma w in %s %s mode - not implemented",
|
||||
ERROR_LOG(SP1, "DMA write in %s %s mode - not implemented",
|
||||
transfer.region == transfer.EXI ? "exi" : "mx",
|
||||
transfer.direction == transfer.READ ? "read" : "write");
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ void CEXIETHERNET::DMAWrite(u32 addr, u32 size)
|
|||
|
||||
void CEXIETHERNET::DMARead(u32 addr, u32 size)
|
||||
{
|
||||
DEBUG_LOG(SP1, "dma r: %08x %x", addr, size);
|
||||
DEBUG_LOG(SP1, "DMA read: %08x %x", addr, size);
|
||||
|
||||
memcpy(Memory::GetPointer(addr), &mBbaMem[transfer.address], size);
|
||||
|
||||
|
@ -382,7 +382,7 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
|
|||
case BBA_NCRA:
|
||||
if (data & NCRA_RESET)
|
||||
{
|
||||
DEBUG_LOG(SP1, "software reset");
|
||||
DEBUG_LOG(SP1, "Software reset");
|
||||
//MXSoftReset();
|
||||
Activate();
|
||||
}
|
||||
|
@ -400,16 +400,16 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
|
|||
// Only start transfer if there isn't one currently running
|
||||
if (!(mBbaMem[BBA_NCRA] & (NCRA_ST0 | NCRA_ST1)))
|
||||
{
|
||||
// Technically transfer dma status is kept in TXDMA - not implemented
|
||||
// Technically transfer DMA status is kept in TXDMA - not implemented
|
||||
|
||||
if (data & NCRA_ST0)
|
||||
{
|
||||
WARN_LOG(SP1, "start tx - local dma");
|
||||
WARN_LOG(SP1, "start tx - local DMA");
|
||||
SendFromPacketBuffer();
|
||||
}
|
||||
else if (data & NCRA_ST1)
|
||||
{
|
||||
DEBUG_LOG(SP1, "start tx - direct fifo");
|
||||
DEBUG_LOG(SP1, "start tx - direct FIFO");
|
||||
SendFromDirectFIFO();
|
||||
// Kind of a hack: send completes instantly, so we don't
|
||||
// actually write the "send in status" bit to the register
|
||||
|
@ -451,7 +451,7 @@ void CEXIETHERNET::DirectFIFOWrite(u8 *data, u32 size)
|
|||
memcpy(tx_fifo + *tx_fifo_count, data, size);
|
||||
|
||||
*tx_fifo_count += size;
|
||||
// TODO not sure this mask is correct.
|
||||
// TODO: not sure this mask is correct.
|
||||
// However, BBA_TXFIFOCNT should never get even close to this amount,
|
||||
// so it shouldn't matter
|
||||
*tx_fifo_count &= (1 << 12) - 1;
|
||||
|
@ -464,7 +464,7 @@ void CEXIETHERNET::SendFromDirectFIFO()
|
|||
|
||||
void CEXIETHERNET::SendFromPacketBuffer()
|
||||
{
|
||||
ERROR_LOG(SP1, "tx packet buffer not implemented");
|
||||
ERROR_LOG(SP1, "tx packet buffer not implemented.");
|
||||
}
|
||||
|
||||
void CEXIETHERNET::SendComplete()
|
||||
|
@ -484,7 +484,7 @@ void CEXIETHERNET::SendComplete()
|
|||
|
||||
inline u8 CEXIETHERNET::HashIndex(u8 *dest_eth_addr)
|
||||
{
|
||||
// Calculate crc
|
||||
// Calculate CRC
|
||||
u32 crc = 0xffffffff;
|
||||
|
||||
for (size_t byte_num = 0; byte_num < 6; ++byte_num)
|
||||
|
@ -601,7 +601,7 @@ bool CEXIETHERNET::RecvHandlePacket()
|
|||
if (AUTORCVR)
|
||||
discard bad packet
|
||||
else
|
||||
inc MPC instad of recving packets
|
||||
inc MPC instead of receiving packets
|
||||
*/
|
||||
status |= DESC_FO | DESC_BF;
|
||||
mBbaMem[BBA_IR] |= mBbaMem[BBA_IMR] & INT_RBF;
|
||||
|
|
|
@ -222,7 +222,7 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
|
|||
}
|
||||
|
||||
default:
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "Uknown USBGecko command %x", _uData);
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "Unknown USBGecko command %x", _uData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// note that userdata is forbidden to be a pointer, due to the implemenation of EventDoState
|
||||
// note that userdata is forbidden to be a pointer, due to the implementation of EventDoState
|
||||
int card_index = (int)userdata;
|
||||
CEXIMemoryCard* pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index);
|
||||
if (pThis)
|
||||
|
@ -86,7 +86,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
|||
//0x00000510 16Mb "bigben" card
|
||||
//card_id = 0xc243;
|
||||
|
||||
card_id = 0xc221; // It's a nintendo brand memcard
|
||||
card_id = 0xc221; // It's a Nintendo brand memcard
|
||||
|
||||
File::IOFile pFile(m_strFilename, "rb");
|
||||
if (pFile)
|
||||
|
@ -110,7 +110,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
|||
memory_card_content = new u8[memory_card_size];
|
||||
GCMemcard::Format(memory_card_content, m_strFilename.find(".JAP.raw") != std::string::npos, nintendo_card_id);
|
||||
memset(memory_card_content+MC_HDR_SIZE, 0xFF, memory_card_size-MC_HDR_SIZE);
|
||||
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
|
||||
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create a new one.");
|
||||
}
|
||||
SetCardFlashID(memory_card_content, card_index);
|
||||
}
|
||||
|
@ -130,7 +130,9 @@ void innerFlush(FlushData* data)
|
|||
if (!pFile) // Note - pFile changed inside above if
|
||||
{
|
||||
PanicAlertT("Could not write memory card file %s.\n\n"
|
||||
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?", data->filename.c_str());
|
||||
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?\n\n"
|
||||
"Are you receiving this after moving the emulator directory?\nIf so, then you may "
|
||||
"need to re-specify your memory card location in the options.", data->filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -148,6 +150,9 @@ void CEXIMemoryCard::Flush(bool exiting)
|
|||
if(!m_bDirty)
|
||||
return;
|
||||
|
||||
if (!Core::g_CoreStartupParameter.bEnableMemcardSaving)
|
||||
return;
|
||||
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
|
@ -337,11 +342,11 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
|
|||
{
|
||||
case cmdNintendoID:
|
||||
//
|
||||
// nintendo card:
|
||||
// Nintendo card:
|
||||
// 00 | 80 00 00 00 10 00 00 00
|
||||
// "bigben" card:
|
||||
// 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00
|
||||
// we do it the nintendo way.
|
||||
// we do it the Nintendo way.
|
||||
if (m_uPosition == 1)
|
||||
byte = 0x80; // dummy cycle
|
||||
else
|
||||
|
|
|
@ -89,9 +89,11 @@ void GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
|
|||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: PAD_Rumble
|
||||
// Function: Rumble
|
||||
// Purpose: Pad rumble!
|
||||
// input: PAD number, Command type (Stop=0, Rumble=1, Stop Hard=2) and strength of Rumble
|
||||
// input: _numPad - Which pad to rumble.
|
||||
// _uType - Command type (Stop=0, Rumble=1, Stop Hard=2).
|
||||
// _uStrength - Strength of the Rumble
|
||||
// output: none
|
||||
//
|
||||
void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
|
||||
|
@ -116,8 +118,9 @@ void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
|
|||
// __________________________________________________________________________________________________
|
||||
// Function: Motor
|
||||
// Purpose: For devices with constant Force feedback
|
||||
// input: Type - 06 = Motor On, 04 = Motor Off
|
||||
// Strength - 00 = Left Strong, 127 = Left Weak, 128 = Right Weak, 255 = Right Strong
|
||||
// input: _numPAD - The pad to operate on
|
||||
// _uType - 06 = Motor On, 04 = Motor Off
|
||||
// _uStrength - 00 = Left Strong, 127 = Left Weak, 128 = Right Weak, 255 = Right Strong
|
||||
// output: none
|
||||
//
|
||||
void Motor(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
|
||||
|
|
|
@ -124,28 +124,28 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
return;
|
||||
|
||||
case PI_FIFO_BASE:
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "read cpu fifo base, value = %08x", Fifo_CPUBase);
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "Read CPU FIFO base, value = %08x", Fifo_CPUBase);
|
||||
_uReturnValue = Fifo_CPUBase;
|
||||
return;
|
||||
|
||||
case PI_FIFO_END:
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "read cpu fifo end, value = %08x", Fifo_CPUEnd);
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "Read CPU FIFO end, value = %08x", Fifo_CPUEnd);
|
||||
_uReturnValue = Fifo_CPUEnd;
|
||||
return;
|
||||
|
||||
case PI_FIFO_WPTR:
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "read writepointer, value = %08x", Fifo_CPUWritePointer);
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "Read writepointer, value = %08x", Fifo_CPUWritePointer);
|
||||
_uReturnValue = Fifo_CPUWritePointer; //really writes in 32-byte chunks
|
||||
// Monk's gcube does some crazy align trickery here.
|
||||
return;
|
||||
|
||||
case PI_RESET_CODE:
|
||||
INFO_LOG(PROCESSORINTERFACE, "read reset code, 0x%08x", m_ResetCode);
|
||||
INFO_LOG(PROCESSORINTERFACE, "Read reset code, 0x%08x", m_ResetCode);
|
||||
_uReturnValue = m_ResetCode;
|
||||
return;
|
||||
|
||||
case PI_FLIPPER_REV:
|
||||
INFO_LOG(PROCESSORINTERFACE, "read flipper rev, 0x%08x", m_FlipperRev);
|
||||
INFO_LOG(PROCESSORINTERFACE, "Read flipper rev, 0x%08x", m_FlipperRev);
|
||||
_uReturnValue = m_FlipperRev;
|
||||
return;
|
||||
|
||||
|
@ -202,7 +202,7 @@ void Write32(const u32 _uValue, const u32 _iAddress)
|
|||
break;
|
||||
|
||||
case PI_FLIPPER_UNK:
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "write %08x to unknown PI reg %08x", _uValue, _iAddress);
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "Write %08x to unknown PI register %08x", _uValue, _iAddress);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -143,7 +143,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
{
|
||||
case 0x10:
|
||||
{
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 10, %02x (READ STATUS&SWITCHES)", ptr(1));
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 10, %02x (READ STATUS&SWITCHES)", ptr(1));
|
||||
SPADStatus PadStatus;
|
||||
memset(&PadStatus, 0 ,sizeof(PadStatus));
|
||||
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
||||
|
@ -161,13 +161,13 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
break;
|
||||
}
|
||||
case 0x12:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 12, %02x %02x", ptr(1), ptr(2));
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 12, %02x %02x", ptr(1), ptr(2));
|
||||
res[resp++] = 0x12;
|
||||
res[resp++] = 0x00;
|
||||
break;
|
||||
case 0x11:
|
||||
{
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 11, %02x (READ SERIAL NR)", ptr(1));
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 11, %02x (READ SERIAL NR)", ptr(1));
|
||||
char string[] = "AADE-01A14964511";
|
||||
res[resp++] = 0x11;
|
||||
res[resp++] = 0x10;
|
||||
|
@ -183,7 +183,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
res[resp++] = 0x29; // FIRM VERSION
|
||||
break;
|
||||
case 0x16:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 16, %02x (READ FPGA VERSION)", ptr(1));
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 16, %02x (READ FPGA VERSION)", ptr(1));
|
||||
res[resp++] = 0x16;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x07;
|
||||
|
@ -196,7 +196,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
break;
|
||||
case 0x1f:
|
||||
{
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 1f, %02x %02x %02x %02x %02x (REGION)", ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 1f, %02x %02x %02x %02x %02x (REGION)", ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
|
||||
unsigned char string[] =
|
||||
"\x00\x00\x30\x00"
|
||||
//"\x01\xfe\x00\x00" // JAPAN
|
||||
|
@ -211,14 +211,14 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
break;
|
||||
}
|
||||
case 0x31:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 31 (UNKNOWN)");
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 31 (UNKNOWN)");
|
||||
res[resp++] = 0x31;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x00;
|
||||
res[resp++] = 0x00;
|
||||
break;
|
||||
case 0x32:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 32 (UNKNOWN)");
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 32 (UNKNOWN)");
|
||||
res[resp++] = 0x32;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x00;
|
||||
|
@ -241,7 +241,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
case 0x4e:
|
||||
case 0x4f:
|
||||
{
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD %02x, %02x %02x %02x %02x %02x %02x %02x (JVS IO)",
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: Command %02x, %02x %02x %02x %02x %02x %02x %02x (JVS IO)",
|
||||
ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), ptr(6), ptr(7));
|
||||
int pptr = 2;
|
||||
JVSIOMessage msg;
|
||||
|
@ -262,7 +262,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
{
|
||||
|
||||
int cmd = *jvs_io++;
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "JVS IO, node=%d, cmd=%02x", node, cmd);
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "JVS IO, node=%d, command=%02x", node, cmd);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
|
@ -391,10 +391,10 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
break;
|
||||
}
|
||||
case 0x60:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 60, %02x %02x %02x", ptr(1), ptr(2), ptr(3));
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 60, %02x %02x %02x", ptr(1), ptr(2), ptr(3));
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD %02x (unknown) %02x %02x %02x %02x %02x", ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command %02x (unknown) %02x %02x %02x %02x %02x", ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
|
||||
break;
|
||||
}
|
||||
p += ptr(1) + 2;
|
||||
|
@ -414,7 +414,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
log += sprintf(log, "%02x ", ptr(i));
|
||||
}
|
||||
ptr(0x7f) = ~csum;
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "command send back: %s", logptr);
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "Command send back: %s", logptr);
|
||||
#undef ptr
|
||||
|
||||
|
||||
|
@ -438,7 +438,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
// DEFAULT
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
|
||||
PanicAlert("SI: Unknown command");
|
||||
iPosition = _iLength;
|
||||
}
|
||||
|
@ -460,6 +460,6 @@ bool CSIDevice_AMBaseboard::GetData(u32& _Hi, u32& _Low)
|
|||
|
||||
void CSIDevice_AMBaseboard::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
|
||||
PanicAlert("SI: (GCAM) Unknown direct command");
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ void GBASockServer::Transfer(char* si_buffer)
|
|||
else
|
||||
client.Send(current_data, 1);
|
||||
|
||||
DEBUG_LOG(SERIALINTERFACE, "> cmd %02x %02x%02x%02x%02x",
|
||||
DEBUG_LOG(SERIALINTERFACE, "> command %02x %02x%02x%02x%02x",
|
||||
(u8)current_data[0], (u8)current_data[1], (u8)current_data[2],
|
||||
(u8)current_data[3], (u8)current_data[4]);
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
// DEFAULT
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
|
||||
PanicAlert("SI: Unknown command (0x%x)", command);
|
||||
}
|
||||
break;
|
||||
|
@ -275,7 +275,7 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll)
|
|||
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
|
||||
PanicAlert("SI: Unknown direct command");
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -99,7 +99,7 @@ int CSIDevice_GCSteeringWheel::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
// DEFAULT
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ void CSIDevice_GCSteeringWheel::SendCommand(u32 _Cmd, u8 _Poll)
|
|||
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -243,29 +243,29 @@ void PreInit()
|
|||
|
||||
void Init()
|
||||
{
|
||||
const int fields = SConfig::GetInstance().m_LocalCoreStartupParameter.bVBeam ? 2 : 1;
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||
{
|
||||
if (!DSP::GetDSPEmulator()->IsLLE())
|
||||
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
|
||||
|
||||
// AyuanX: TO BE TWEAKED
|
||||
// Now the 1500 is a pure assumption
|
||||
// We need to figure out the real frequency though
|
||||
|
||||
// FYI, WII_IPC_HLE_Interface::Update is also called in WII_IPCInterface::Write32
|
||||
const int freq = 1500;
|
||||
const int fields = SConfig::GetInstance().m_LocalCoreStartupParameter.
|
||||
bVBeam ? 2 : 1;
|
||||
IPC_HLE_PERIOD = GetTicksPerSecond() / (freq * fields);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DSP::GetDSPEmulator()->IsLLE())
|
||||
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f);
|
||||
}
|
||||
|
||||
if (DSP::GetDSPEmulator()->IsLLE())
|
||||
DSP_PERIOD = 12000; // TO BE TWEAKED
|
||||
{
|
||||
DSP_PERIOD = 12600; // TO BE TWEAKED
|
||||
}
|
||||
else
|
||||
{
|
||||
// AX HLE uses 3ms (Wii) or 5ms (GC) timing period
|
||||
int ms_to_process = SConfig::GetInstance().m_LocalCoreStartupParameter.bWii ? 3 : 5;
|
||||
DSP_PERIOD = (int)(GetTicksPerSecond() / 1000) * ms_to_process / fields;
|
||||
}
|
||||
|
||||
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
|
||||
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (AudioInterface::GetAIDSampleRate() * 4 / 32);
|
||||
|
|
|
@ -407,11 +407,11 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
|
|||
|
||||
case VI_UNK_AA_REG_HI:
|
||||
_uReturnValue = (m_UnkAARegister & 0xffff0000) >> 16;
|
||||
WARN_LOG(VIDEOINTERFACE, "(r16) unknown AA reg, not sure what it does :)");
|
||||
WARN_LOG(VIDEOINTERFACE, "(r16) unknown AA register, not sure what it does :)");
|
||||
break;
|
||||
case VI_UNK_AA_REG_LO:
|
||||
_uReturnValue = m_UnkAARegister & 0x0000ffff;
|
||||
WARN_LOG(VIDEOINTERFACE, "(r16) unknown AA reg, not sure what it does :)");
|
||||
WARN_LOG(VIDEOINTERFACE, "(r16) unknown AA register, not sure what it does :)");
|
||||
break;
|
||||
|
||||
case VI_CLOCK:
|
||||
|
@ -434,7 +434,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
|
|||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(VIDEOINTERFACE, "(r16) unk reg %x", _iAddress & 0xfff);
|
||||
ERROR_LOG(VIDEOINTERFACE, "(r16) unknown reg %x", _iAddress & 0xfff);
|
||||
_uReturnValue = 0x0;
|
||||
break;
|
||||
}
|
||||
|
@ -659,11 +659,11 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
|||
|
||||
case VI_UNK_AA_REG_HI:
|
||||
m_UnkAARegister = (m_UnkAARegister & 0x0000ffff) | (u32)(_iValue << 16);
|
||||
WARN_LOG(VIDEOINTERFACE, "(w16) to unknown AA reg, not sure what it does :)");
|
||||
WARN_LOG(VIDEOINTERFACE, "(w16) to unknown AA register, not sure what it does :)");
|
||||
break;
|
||||
case VI_UNK_AA_REG_LO:
|
||||
m_UnkAARegister = (m_UnkAARegister & 0xffff0000) | _iValue;
|
||||
WARN_LOG(VIDEOINTERFACE, "(w16) to unknown AA reg, not sure what it does :)");
|
||||
WARN_LOG(VIDEOINTERFACE, "(w16) to unknown AA register, not sure what it does :)");
|
||||
break;
|
||||
|
||||
case VI_CLOCK:
|
||||
|
@ -686,7 +686,7 @@ void Write16(const u16 _iValue, const u32 _iAddress)
|
|||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(VIDEOINTERFACE, "(w16) %04x to unk reg %x", _iValue, _iAddress & 0xfff);
|
||||
ERROR_LOG(VIDEOINTERFACE, "(w16) %04x to unknown register %x", _iValue, _iAddress & 0xfff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -812,7 +812,7 @@ static void BeginField(FieldType field)
|
|||
|
||||
static const char* const fieldTypeNames[] = { "Progressive", "Upper", "Lower" };
|
||||
|
||||
DEBUG_LOG(VIDEOINTERFACE, "(VI->BeginField): addr: %.08X | FieldSteps %u | FbSteps %u | ACV %u | Field %s",
|
||||
DEBUG_LOG(VIDEOINTERFACE, "(VI->BeginField): Address: %.08X | FieldSteps %u | FbSteps %u | ACV %u | Field %s",
|
||||
xfbAddr, m_HorizontalStepping.FieldSteps, m_HorizontalStepping.FbSteps, m_VerticalTimingRegister.ACV,
|
||||
fieldTypeNames[field]
|
||||
);
|
||||
|
|
|
@ -194,7 +194,7 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
_Value, ctrl.ppc(), ctrl.Y1, ctrl.Y2, ctrl.X1);
|
||||
if (ctrl.X1)
|
||||
{
|
||||
INFO_LOG(WII_IPC, "new pointer available: %08x", ppc_msg);
|
||||
INFO_LOG(WII_IPC, "New pointer available: %08x", ppc_msg);
|
||||
// Let the HLE handle the request on it's own time
|
||||
WII_IPC_HLE_Interface::EnqRequest(ppc_msg);
|
||||
}
|
||||
|
|
|
@ -55,11 +55,16 @@ void Initialize(void* const hwnd)
|
|||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: Wiimote_Output
|
||||
// Function: ControlChannel
|
||||
// Purpose: An L2CAP packet is passed from the Core to the Wiimote,
|
||||
// on the HID CONTROL channel.
|
||||
// input: Da pakket.
|
||||
// output: none
|
||||
//
|
||||
// Inputs: _number [Description needed]
|
||||
// _channelID [Description needed]
|
||||
// _pData [Description needed]
|
||||
// _Size [Description needed]
|
||||
//
|
||||
// Output: none
|
||||
//
|
||||
void ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
||||
{
|
||||
|
@ -71,11 +76,16 @@ void ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
|||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: Wiimote_InterruptChannel
|
||||
// Function: InterruptChannel
|
||||
// Purpose: An L2CAP packet is passed from the Core to the Wiimote,
|
||||
// on the HID INTERRUPT channel.
|
||||
// input: Da pakket.
|
||||
// output: none
|
||||
//
|
||||
// Inputs: _number [Description needed]
|
||||
// _channelID [Description needed]
|
||||
// _pData [Description needed]
|
||||
// _Size [Description needed]
|
||||
//
|
||||
// Output: none
|
||||
//
|
||||
void InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
||||
{
|
||||
|
@ -86,9 +96,9 @@ void InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size
|
|||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: Wiimote_Update
|
||||
// Purpose: This function is called periodically by the Core.
|
||||
// input: none
|
||||
// Function: Update
|
||||
// Purpose: This function is called periodically by the Core. // TODO: Explain why.
|
||||
// input: _number: [Description needed]
|
||||
// output: none
|
||||
//
|
||||
void Update(int _number)
|
||||
|
@ -113,10 +123,10 @@ void Update(int _number)
|
|||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: PAD_GetAttachedPads
|
||||
// Function: GetAttached
|
||||
// Purpose: Get mask of attached pads (eg: controller 1 & 4 -> 0x9)
|
||||
// input: none
|
||||
// output: number of pads
|
||||
// input: none
|
||||
// output: The number of attached pads
|
||||
//
|
||||
unsigned int GetAttached()
|
||||
{
|
||||
|
@ -130,8 +140,8 @@ unsigned int GetAttached()
|
|||
// ___________________________________________________________________________
|
||||
// Function: DoState
|
||||
// Purpose: Saves/load state
|
||||
// input/output: ptr
|
||||
// input: mode
|
||||
// input/output: ptr: [Description Needed]
|
||||
// input: mode [Description needed]
|
||||
//
|
||||
void DoState(u8 **ptr, PointerWrap::Mode mode)
|
||||
{
|
||||
|
@ -145,7 +155,7 @@ void DoState(u8 **ptr, PointerWrap::Mode mode)
|
|||
// ___________________________________________________________________________
|
||||
// Function: EmuStateChange
|
||||
// Purpose: Notifies the plugin of a change in emulation state
|
||||
// input: newState
|
||||
// input: newState - The new state for the Wiimote to change to.
|
||||
// output: none
|
||||
//
|
||||
void EmuStateChange(EMUSTATE_CHANGE newState)
|
||||
|
|
|
@ -360,7 +360,7 @@ void Wiimote::WriteData(const wm_write_data* const wd)
|
|||
/* TODO?
|
||||
if (region_ptr == &m_reg_speaker)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Write to speaker reg %x %s", address,
|
||||
ERROR_LOG(WIIMOTE, "Write to speaker register %x %s", address,
|
||||
ArrayToString(wd->data, wd->size, 100, false).c_str());
|
||||
}
|
||||
*/
|
||||
|
@ -511,7 +511,7 @@ void Wiimote::ReadData(const wm_read_data* const rd)
|
|||
break;
|
||||
|
||||
default :
|
||||
PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size, rd->space);
|
||||
PanicAlert("WmReadData: unimplemented parameters (size: %i, address: 0x%x)!", size, rd->space);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -707,10 +707,10 @@ void Wiimote::Update()
|
|||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||
if (g_wiimotes[m_index])
|
||||
{
|
||||
Report rpt = g_wiimotes[m_index]->ProcessReadQueue();
|
||||
const u8 *real_data = rpt.first;
|
||||
if (real_data)
|
||||
const Report& rpt = g_wiimotes[m_index]->ProcessReadQueue();
|
||||
if (!rpt.empty())
|
||||
{
|
||||
const u8 *real_data = rpt.data();
|
||||
switch (real_data[1])
|
||||
{
|
||||
// use data reports
|
||||
|
@ -770,13 +770,9 @@ void Wiimote::Update()
|
|||
// copy over report from real-wiimote
|
||||
if (-1 == rptf_size)
|
||||
{
|
||||
memcpy(data, real_data, rpt.second);
|
||||
rptf_size = rpt.second;
|
||||
std::copy(rpt.begin(), rpt.end(), data);
|
||||
rptf_size = rpt.size();
|
||||
}
|
||||
|
||||
if (real_data != g_wiimotes[m_index]->\
|
||||
m_last_data_report.first)
|
||||
delete[] real_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,7 +300,7 @@ bool Wiimote::Connect()
|
|||
TCHAR name[128] = {};
|
||||
HidD_GetProductString(dev_handle, name, 128);
|
||||
|
||||
//ERROR_LOG(WIIMOTE, "product string: %s", TStrToUTF8(name).c_str());
|
||||
//ERROR_LOG(WIIMOTE, "Product string: %s", TStrToUTF8(name).c_str());
|
||||
|
||||
if (!IsValidBluetoothName(TStrToUTF8(name)))
|
||||
{
|
||||
|
@ -333,7 +333,7 @@ bool Wiimote::Connect()
|
|||
/*
|
||||
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Failed to set wiimote thread priority");
|
||||
ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority");
|
||||
}
|
||||
*/
|
||||
#ifdef SHARE_WRITE_WIIMOTES
|
||||
|
@ -370,73 +370,55 @@ bool Wiimote::IsConnected() const
|
|||
// zero = error
|
||||
int Wiimote::IORead(u8* buf)
|
||||
{
|
||||
// used below for a warning
|
||||
*buf = 0;
|
||||
// Add data report indicator byte (here, 0xa1)
|
||||
buf[0] = 0xa1;
|
||||
// Used below for a warning
|
||||
buf[1] = 0;
|
||||
|
||||
DWORD bytes;
|
||||
DWORD bytes = 0;
|
||||
ResetEvent(hid_overlap_read.hEvent);
|
||||
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
|
||||
if (!ReadFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
|
||||
{
|
||||
auto const err = GetLastError();
|
||||
auto const read_err = GetLastError();
|
||||
|
||||
if (ERROR_IO_PENDING == err)
|
||||
if (ERROR_IO_PENDING == read_err)
|
||||
{
|
||||
auto const r = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
||||
if (WAIT_TIMEOUT == r)
|
||||
auto const wait_result = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
||||
if (WAIT_TIMEOUT == wait_result)
|
||||
{
|
||||
// Timeout - cancel and continue
|
||||
if (*buf)
|
||||
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).",
|
||||
CancelIo(dev_handle);
|
||||
}
|
||||
else if (WAIT_FAILED == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "A wait error occurred on reading from Wiimote %i.", index + 1);
|
||||
CancelIo(dev_handle);
|
||||
}
|
||||
|
||||
if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE))
|
||||
{
|
||||
auto const overlapped_err = GetLastError();
|
||||
|
||||
if (ERROR_OPERATION_ABORTED == overlapped_err)
|
||||
{
|
||||
if (buf[1] != 0)
|
||||
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).",
|
||||
WIIMOTE_DEFAULT_TIMEOUT);
|
||||
|
||||
CancelIo(dev_handle);
|
||||
bytes = -1;
|
||||
}
|
||||
else if (WAIT_FAILED == r)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "A wait error occured on reading from wiimote %i.", index + 1);
|
||||
bytes = 0;
|
||||
}
|
||||
else if (WAIT_OBJECT_0 == r)
|
||||
{
|
||||
if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE))
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1);
|
||||
bytes = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WARN_LOG(WIIMOTE, "GetOverlappedResult error %d on Wiimote %i.", overlapped_err, index + 1);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = 0;
|
||||
}
|
||||
}
|
||||
else if (ERROR_HANDLE_EOF == err)
|
||||
{
|
||||
// Remote disconnect
|
||||
bytes = 0;
|
||||
}
|
||||
else if (ERROR_DEVICE_NOT_CONNECTED == err)
|
||||
{
|
||||
// Remote disconnect
|
||||
bytes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = 0;
|
||||
WARN_LOG(WIIMOTE, "ReadFile error %d on Wiimote %i.", read_err, index + 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
// Move the data over one, so we can add back in data report indicator byte (here, 0xa1)
|
||||
std::copy_n(buf, MAX_PAYLOAD - 1, buf + 1);
|
||||
buf[0] = 0xa1;
|
||||
|
||||
// TODO: is this really needed?
|
||||
bytes = MAX_PAYLOAD;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
return bytes + 1;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(const u8* buf, int len)
|
||||
|
@ -468,7 +450,7 @@ int Wiimote::IOWrite(const u8* buf, int len)
|
|||
if (err == 121)
|
||||
{
|
||||
// Semaphore timeout
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to the Wiimote");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -553,8 +535,8 @@ void ProcessWiimotes(bool new_scan, T& callback)
|
|||
HBLUETOOTH_DEVICE_FIND hFindDevice = Bth_BluetoothFindFirstDevice(&srch, &btdi);
|
||||
while (hFindDevice)
|
||||
{
|
||||
// btdi.szName is sometimes missings it's content - it's a bt feature..
|
||||
DEBUG_LOG(WIIMOTE, "authed %i connected %i remembered %i ",
|
||||
// btdi.szName is sometimes missing it's content - it's a bt feature..
|
||||
DEBUG_LOG(WIIMOTE, "Authenticated %i connected %i remembered %i ",
|
||||
btdi.fAuthenticated, btdi.fConnected, btdi.fRemembered);
|
||||
|
||||
if (IsValidBluetoothName(UTF16ToUTF8(btdi.szName)))
|
||||
|
@ -597,7 +579,7 @@ bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info, BLUETO
|
|||
{
|
||||
auto const& wm_addr = btdi.Address.rgBytes;
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Found wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.",
|
||||
NOTICE_LOG(WIIMOTE, "Found Wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.",
|
||||
wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]);
|
||||
|
||||
#if defined(AUTHENTICATE_WIIMOTES)
|
||||
|
@ -647,7 +629,7 @@ bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
|||
{
|
||||
// Make Windows forget about device so it will re-find it if visible.
|
||||
// This is also required to detect a disconnect for some reason..
|
||||
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
|
||||
NOTICE_LOG(WIIMOTE, "Removing remembered Wiimote.");
|
||||
Bth_BluetoothRemoveDevice(&btdi.Address);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ Wiimote::Wiimote()
|
|||
#elif defined(_WIN32)
|
||||
, dev_handle(0), stack(MSBT_STACK_UNKNOWN)
|
||||
#endif
|
||||
, m_last_data_report(Report((u8 *)NULL, 0))
|
||||
, m_last_input_report()
|
||||
, m_channel(0), m_run_thread(false)
|
||||
{
|
||||
#if defined(__linux__) && HAVE_BLUEZ
|
||||
|
@ -73,11 +73,7 @@ Wiimote::~Wiimote()
|
|||
Disconnect();
|
||||
|
||||
ClearReadQueue();
|
||||
|
||||
// clear write queue
|
||||
Report rpt;
|
||||
while (m_write_reports.Pop(rpt))
|
||||
delete[] rpt.first;
|
||||
m_write_reports.Clear();
|
||||
}
|
||||
|
||||
// to be called from CPU thread
|
||||
|
@ -85,17 +81,18 @@ void Wiimote::QueueReport(u8 rpt_id, const void* _data, unsigned int size)
|
|||
{
|
||||
auto const data = static_cast<const u8*>(_data);
|
||||
|
||||
Report rpt;
|
||||
rpt.second = size + 2;
|
||||
rpt.first = new u8[rpt.second];
|
||||
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
||||
rpt.first[1] = rpt_id;
|
||||
std::copy(data, data + size, rpt.first + 2);
|
||||
m_write_reports.Push(rpt);
|
||||
Report rpt(size + 2);
|
||||
rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
||||
rpt[1] = rpt_id;
|
||||
std::copy_n(data, size, rpt.begin() + 2);
|
||||
m_write_reports.Push(std::move(rpt));
|
||||
}
|
||||
|
||||
void Wiimote::DisableDataReporting()
|
||||
{
|
||||
m_last_input_report.clear();
|
||||
|
||||
// This probably accomplishes nothing.
|
||||
wm_report_mode rpt = {};
|
||||
rpt.mode = WM_REPORT_CORE;
|
||||
rpt.all_the_time = 0;
|
||||
|
@ -107,15 +104,10 @@ void Wiimote::DisableDataReporting()
|
|||
void Wiimote::ClearReadQueue()
|
||||
{
|
||||
Report rpt;
|
||||
|
||||
if (m_last_data_report.first)
|
||||
{
|
||||
delete[] m_last_data_report.first;
|
||||
m_last_data_report.first = NULL;
|
||||
}
|
||||
|
||||
|
||||
// The "Clear" function isn't thread-safe :/
|
||||
while (m_read_reports.Pop(rpt))
|
||||
delete[] rpt.first;
|
||||
{}
|
||||
}
|
||||
|
||||
void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size)
|
||||
|
@ -148,65 +140,58 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const
|
|||
}
|
||||
|
||||
auto const data = static_cast<const u8*>(_data);
|
||||
|
||||
Report rpt;
|
||||
rpt.first = new u8[size];
|
||||
rpt.second = (u8)size;
|
||||
std::copy(data, data + size, rpt.first);
|
||||
Report rpt(data, data + size);
|
||||
|
||||
// Convert output DATA packets to SET_REPORT packets.
|
||||
// Nintendo Wiimotes work without this translation, but 3rd
|
||||
// party ones don't.
|
||||
if (rpt.first[0] == 0xa2)
|
||||
if (rpt[0] == 0xa2)
|
||||
{
|
||||
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
||||
rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
||||
}
|
||||
|
||||
// Disallow games from turning off all of the LEDs.
|
||||
// It makes wiimote connection status confusing.
|
||||
if (rpt.first[1] == WM_LEDS)
|
||||
// It makes Wiimote connection status confusing.
|
||||
if (rpt[1] == WM_LEDS)
|
||||
{
|
||||
auto& leds_rpt = *reinterpret_cast<wm_leds*>(&rpt.first[2]);
|
||||
auto& leds_rpt = *reinterpret_cast<wm_leds*>(&rpt[2]);
|
||||
if (0 == leds_rpt.leds)
|
||||
{
|
||||
// Turn on ALL of the LEDs.
|
||||
leds_rpt.leds = 0xf;
|
||||
}
|
||||
}
|
||||
else if (rpt.first[1] == WM_WRITE_SPEAKER_DATA
|
||||
else if (rpt[1] == WM_WRITE_SPEAKER_DATA
|
||||
&& !SConfig::GetInstance().m_WiimoteEnableSpeaker)
|
||||
{
|
||||
// Translate speaker data reports into rumble reports.
|
||||
rpt.first[1] = WM_CMD_RUMBLE;
|
||||
rpt[1] = WM_RUMBLE;
|
||||
// Keep only the rumble bit.
|
||||
rpt.first[2] &= 0x1;
|
||||
rpt.second = 3;
|
||||
rpt[2] &= 0x1;
|
||||
rpt.resize(3);
|
||||
}
|
||||
|
||||
m_write_reports.Push(rpt);
|
||||
m_write_reports.Push(std::move(rpt));
|
||||
}
|
||||
|
||||
bool Wiimote::Read()
|
||||
{
|
||||
Report rpt;
|
||||
|
||||
rpt.first = new unsigned char[MAX_PAYLOAD];
|
||||
rpt.second = IORead(rpt.first);
|
||||
Report rpt(MAX_PAYLOAD);
|
||||
auto const result = IORead(rpt.data());
|
||||
|
||||
if (0 == rpt.second)
|
||||
if (result > 0 && m_channel > 0)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting wiimote %d.", index + 1);
|
||||
// Add it to queue
|
||||
rpt.resize(result);
|
||||
m_read_reports.Push(std::move(rpt));
|
||||
return true;
|
||||
}
|
||||
else if (0 == result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", index + 1);
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
if (rpt.second > 0 && m_channel > 0)
|
||||
{
|
||||
// Add it to queue
|
||||
m_read_reports.Push(rpt);
|
||||
return true;
|
||||
}
|
||||
|
||||
delete[] rpt.first;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -216,16 +201,15 @@ bool Wiimote::Write()
|
|||
{
|
||||
Report const& rpt = m_write_reports.Front();
|
||||
|
||||
bool const is_speaker_data = rpt.first[1] == WM_WRITE_SPEAKER_DATA;
|
||||
bool const is_speaker_data = rpt[1] == WM_WRITE_SPEAKER_DATA;
|
||||
|
||||
if (!is_speaker_data || m_last_audio_report.GetTimeDifference() > 5)
|
||||
{
|
||||
IOWrite(rpt.first, rpt.second);
|
||||
IOWrite(rpt.data(), rpt.size());
|
||||
|
||||
if (is_speaker_data)
|
||||
m_last_audio_report.Update();
|
||||
|
||||
delete[] rpt.first;
|
||||
m_write_reports.Pop();
|
||||
return true;
|
||||
}
|
||||
|
@ -234,23 +218,35 @@ bool Wiimote::Write()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool IsDataReport(const Report& rpt)
|
||||
{
|
||||
return rpt.size() >= 2 && rpt[1] >= WM_REPORT_CORE;
|
||||
}
|
||||
|
||||
// Returns the next report that should be sent
|
||||
Report Wiimote::ProcessReadQueue()
|
||||
const Report& Wiimote::ProcessReadQueue()
|
||||
{
|
||||
// Pop through the queued reports
|
||||
Report rpt = m_last_data_report;
|
||||
while (m_read_reports.Pop(rpt))
|
||||
while (m_read_reports.Pop(m_last_input_report))
|
||||
{
|
||||
if (rpt.first[1] >= WM_REPORT_CORE)
|
||||
// A data report
|
||||
m_last_data_report = rpt;
|
||||
else
|
||||
// Some other kind of report
|
||||
return rpt;
|
||||
if (!IsDataReport(m_last_input_report))
|
||||
{
|
||||
// A non-data report, use it.
|
||||
return m_last_input_report;
|
||||
|
||||
// Forget the last data report as it may be of the wrong type
|
||||
// or contain outdated button data
|
||||
// or it's not supposed to be sent at this time
|
||||
// It's just easier to be correct this way and it's probably not horrible.
|
||||
}
|
||||
}
|
||||
|
||||
// The queue was empty, or there were only data reports
|
||||
return rpt;
|
||||
// If the last report wasn't a data report it's irrelevant.
|
||||
if (!IsDataReport(m_last_input_report))
|
||||
m_last_input_report.clear();
|
||||
|
||||
// If it was a data report, we repeat that until something else comes in.
|
||||
return m_last_input_report;
|
||||
}
|
||||
|
||||
void Wiimote::Update()
|
||||
|
@ -262,16 +258,12 @@ void Wiimote::Update()
|
|||
}
|
||||
|
||||
// Pop through the queued reports
|
||||
Report const rpt = ProcessReadQueue();
|
||||
const Report& rpt = ProcessReadQueue();
|
||||
|
||||
// Send the report
|
||||
if (rpt.first != NULL && m_channel > 0)
|
||||
if (!rpt.empty() && m_channel > 0)
|
||||
Core::Callback_WiimoteInterruptChannel(index, m_channel,
|
||||
rpt.first, rpt.second);
|
||||
|
||||
// Delete the data if it isn't also the last data rpt
|
||||
if (rpt != m_last_data_report)
|
||||
delete[] rpt.first;
|
||||
rpt.data(), rpt.size());
|
||||
}
|
||||
|
||||
bool Wiimote::Prepare(int _index)
|
||||
|
@ -279,13 +271,13 @@ bool Wiimote::Prepare(int _index)
|
|||
index = _index;
|
||||
|
||||
// core buttons, no continuous reporting
|
||||
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30};
|
||||
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE};
|
||||
|
||||
// Set the active LEDs and turn on rumble.
|
||||
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index | 0x1)};
|
||||
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << index | 0x1)};
|
||||
|
||||
// Turn off rumble
|
||||
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0};
|
||||
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0};
|
||||
|
||||
// Request status report
|
||||
u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
|
||||
|
@ -308,12 +300,12 @@ void Wiimote::EmuStop()
|
|||
|
||||
DisableDataReporting();
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Stopping wiimote data reporting");
|
||||
NOTICE_LOG(WIIMOTE, "Stopping Wiimote data reporting.");
|
||||
}
|
||||
|
||||
unsigned int CalculateWantedWiimotes()
|
||||
{
|
||||
// Figure out how many real wiimotes are required
|
||||
// Figure out how many real Wiimotes are required
|
||||
unsigned int wanted_wiimotes = 0;
|
||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i])
|
||||
|
@ -329,7 +321,7 @@ void WiimoteScanner::WantWiimotes(bool do_want)
|
|||
|
||||
void WiimoteScanner::StartScanning()
|
||||
{
|
||||
if (!m_run_thread && IsReady())
|
||||
if (!m_run_thread)
|
||||
{
|
||||
m_run_thread = true;
|
||||
m_scan_thread = std::thread(std::mem_fun(&WiimoteScanner::ThreadFunc), this);
|
||||
|
@ -358,13 +350,13 @@ void WiimoteScanner::ThreadFunc()
|
|||
{
|
||||
Common::SetCurrentThreadName("Wiimote Scanning Thread");
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Wiimote scanning has started");
|
||||
NOTICE_LOG(WIIMOTE, "Wiimote scanning has started.");
|
||||
|
||||
while (m_run_thread)
|
||||
{
|
||||
std::vector<Wiimote*> found_wiimotes;
|
||||
|
||||
//NOTICE_LOG(WIIMOTE, "in loop");
|
||||
//NOTICE_LOG(WIIMOTE, "In loop");
|
||||
|
||||
if (m_want_wiimotes)
|
||||
found_wiimotes = FindWiimotes();
|
||||
|
@ -374,7 +366,7 @@ void WiimoteScanner::ThreadFunc()
|
|||
Update();
|
||||
}
|
||||
|
||||
//NOTICE_LOG(WIIMOTE, "after update");
|
||||
//NOTICE_LOG(WIIMOTE, "After update");
|
||||
|
||||
// TODO: this is a fairly lame place for this
|
||||
CheckForDisconnectedWiimotes();
|
||||
|
@ -385,7 +377,7 @@ void WiimoteScanner::ThreadFunc()
|
|||
Common::SleepCurrentThread(500);
|
||||
}
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped");
|
||||
NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped.");
|
||||
}
|
||||
|
||||
void Wiimote::StartThread()
|
||||
|
@ -485,7 +477,7 @@ void ChangeWiimoteSource(unsigned int index, int source)
|
|||
DoneWithWiimote(index);
|
||||
}
|
||||
|
||||
// reconnect to emu
|
||||
// reconnect to the emulator
|
||||
Host_ConnectWiimote(index, false);
|
||||
if (WIIMOTE_SRC_EMU & source)
|
||||
Host_ConnectWiimote(index, true);
|
||||
|
@ -502,7 +494,7 @@ void TryToConnectWiimote(Wiimote* wm)
|
|||
{
|
||||
if (wm->Connect() && wm->Prepare(i))
|
||||
{
|
||||
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1);
|
||||
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1);
|
||||
|
||||
std::swap(g_wiimotes[i], wm);
|
||||
g_wiimotes[i]->StartThread();
|
||||
|
@ -528,7 +520,7 @@ void DoneWithWiimote(int index)
|
|||
{
|
||||
g_wiimotes[index]->StopThread();
|
||||
|
||||
// First see if we can use this real wiimote in another slot.
|
||||
// First see if we can use this real Wiimote in another slot.
|
||||
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
|
||||
{
|
||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]
|
||||
|
@ -546,7 +538,7 @@ void DoneWithWiimote(int index)
|
|||
}
|
||||
}
|
||||
|
||||
// else, just disconnect the wiimote
|
||||
// else, just disconnect the Wiimote
|
||||
HandleWiimoteDisconnect(index);
|
||||
}
|
||||
|
||||
|
@ -563,7 +555,7 @@ void HandleWiimoteDisconnect(int index)
|
|||
if (wm)
|
||||
{
|
||||
delete wm;
|
||||
NOTICE_LOG(WIIMOTE, "Disconnected wiimote %i.", index + 1);
|
||||
NOTICE_LOG(WIIMOTE, "Disconnected Wiimote %i.", index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,7 +575,7 @@ void Refresh()
|
|||
|
||||
if (0 != CalculateWantedWiimotes())
|
||||
{
|
||||
// Don't hang dolphin when searching
|
||||
// Don't hang Dolphin when searching
|
||||
lk.unlock();
|
||||
found_wiimotes = g_wiimote_scanner.FindWiimotes();
|
||||
lk.lock();
|
||||
|
@ -591,7 +583,7 @@ void Refresh()
|
|||
|
||||
CheckForDisconnectedWiimotes();
|
||||
|
||||
// Brief rumble for already connected wiimotes.
|
||||
// Brief rumble for already connected Wiimotes.
|
||||
for (int i = 0; i != MAX_WIIMOTES; ++i)
|
||||
{
|
||||
if (g_wiimotes[i])
|
||||
|
@ -633,7 +625,7 @@ void Update(int _WiimoteNumber)
|
|||
if (g_wiimotes[_WiimoteNumber])
|
||||
g_wiimotes[_WiimoteNumber]->Update();
|
||||
|
||||
// Wiimote::Update() may remove the wiimote if it was disconnected.
|
||||
// Wiimote::Update() may remove the Wiimote if it was disconnected.
|
||||
if (!g_wiimotes[_WiimoteNumber])
|
||||
{
|
||||
Host_ConnectWiimote(_WiimoteNumber, false);
|
||||
|
|
|
@ -33,8 +33,7 @@
|
|||
|
||||
#include "../../InputCommon/Src/InputConfig.h"
|
||||
|
||||
// Pointer to data, and size of data
|
||||
typedef std::pair<u8*,u8> Report;
|
||||
typedef std::vector<u8> Report;
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
|
@ -50,7 +49,7 @@ public:
|
|||
void InterruptChannel(const u16 channel, const void* const data, const u32 size);
|
||||
void Update();
|
||||
|
||||
Report ProcessReadQueue();
|
||||
const Report& ProcessReadQueue();
|
||||
|
||||
bool Read();
|
||||
bool Write();
|
||||
|
@ -99,7 +98,7 @@ public:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
Report m_last_data_report;
|
||||
Report m_last_input_report;
|
||||
u16 m_channel;
|
||||
|
||||
private:
|
||||
|
|
|
@ -41,20 +41,6 @@
|
|||
#define WM_SET_REPORT 0xA0
|
||||
#endif
|
||||
|
||||
// TODO: duplicated in WiimoteHid.h
|
||||
// Commands
|
||||
#define WM_CMD_RUMBLE 0x10
|
||||
#define WM_CMD_LED 0x11
|
||||
#define WM_CMD_REPORT_TYPE 0x12
|
||||
#define WM_CMD_IR 0x13
|
||||
#define WM_CMD_SPEAKER_ENABLE 0x14
|
||||
#define WM_CMD_CTRL_STATUS 0x15
|
||||
#define WM_CMD_WRITE_DATA 0x16
|
||||
#define WM_CMD_READ_DATA 0x17
|
||||
#define WM_CMD_SPEAKER_DATA 0x18
|
||||
#define WM_CMD_SPEAKER_MUTE 0x19
|
||||
#define WM_CMD_IR_2 0x1A
|
||||
|
||||
#define WM_BT_INPUT 0x01
|
||||
#define WM_BT_OUTPUT 0x02
|
||||
|
||||
|
@ -73,12 +59,12 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
// Available bluetooth stacks for Windows.
|
||||
typedef enum win_bt_stack_t
|
||||
enum win_bt_stack_t
|
||||
{
|
||||
MSBT_STACK_UNKNOWN,
|
||||
MSBT_STACK_MS,
|
||||
MSBT_STACK_BLUESOLEIL
|
||||
} win_bt_stack_t;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // WIIMOTE_COMM_H
|
||||
|
|
|
@ -523,7 +523,7 @@ void ExecuteCommand(u32 _Address)
|
|||
if (CmdSuccess)
|
||||
{
|
||||
// Ensure replies happen in order, fairly ugly
|
||||
// Without this, tons of games fail now that DI commads have different reply delays
|
||||
// Without this, tons of games fail now that DI commands have different reply delays
|
||||
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
|
||||
|
||||
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
|
||||
|
|
|
@ -223,7 +223,7 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(WII_IPC_DVD, "DVDLowRead: file unkw - (DVDAddr: 0x%llx, Size: 0x%x)",
|
||||
INFO_LOG(WII_IPC_DVD, "DVDLowRead: file unknown - (DVDAddr: 0x%llx, Size: 0x%x)",
|
||||
DVDAddress, Size);
|
||||
}
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(WII_IPC_DVD, "DVDLowSeek: file unkw - (DVDAddr: 0x%llx)",
|
||||
INFO_LOG(WII_IPC_DVD, "DVDLowSeek: file unknown - (DVDAddr: 0x%llx)",
|
||||
DVDAddress);
|
||||
}
|
||||
}
|
||||
|
@ -446,15 +446,15 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
// but it seems we don't need to implement anything
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
WARN_LOG(WII_IPC_DVD, "unimplemented cmd 0x%08x (Buffer 0x%08x, 0x%x)",
|
||||
WARN_LOG(WII_IPC_DVD, "Unimplemented command 0x%08x (Buffer 0x%08x, 0x%x)",
|
||||
Command, _BufferOut, _BufferOutSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(WII_IPC_DVD, "unknown cmd 0x%08x (Buffer 0x%08x, 0x%x)",
|
||||
ERROR_LOG(WII_IPC_DVD, "Unknown command 0x%08x (Buffer 0x%08x, 0x%x)",
|
||||
Command, _BufferOut, _BufferOutSize);
|
||||
|
||||
PanicAlertT("unknown cmd 0x%08x", Command);
|
||||
PanicAlertT("Unknown command 0x%08x", Command);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -497,7 +497,7 @@ int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
|
|||
// case DVDLowReset:
|
||||
// case DVDLowClosePartition:
|
||||
default:
|
||||
// ranom numbers here!
|
||||
// random numbers here!
|
||||
// More than ~1/2000th of a second hangs DKCR with DSP HLE, maybe.
|
||||
return SystemTimers::GetTicksPerSecond() / 15000;
|
||||
break;
|
||||
|
|
|
@ -186,7 +186,7 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
|||
{
|
||||
if (m_Mode == ISFS_OPEN_WRITE)
|
||||
{
|
||||
WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to read 0x%x bytes to 0x%08x on write-only file %s", Size, Address, m_Name.c_str());
|
||||
WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to read 0x%x bytes to 0x%08x on a write-only file %s", Size, Address, m_Name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -225,7 +225,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
|||
{
|
||||
if (m_Mode == ISFS_OPEN_READ)
|
||||
{
|
||||
WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to write 0x%x bytes from 0x%08x to read-only file %s", Size, Address, m_Name.c_str());
|
||||
WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to write 0x%x bytes from 0x%08x to a read-only file %s", Size, Address, m_Name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -112,7 +112,7 @@ bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
|
|||
|
||||
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
||||
if (m_Active)
|
||||
INFO_LOG(WII_IPC_ES, "Device was ReOpened");
|
||||
INFO_LOG(WII_IPC_ES, "Device was re-opened.");
|
||||
m_Active = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
}
|
||||
}
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Addr 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_pContent->m_Index);
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_pContent->m_Index);
|
||||
|
||||
Memory::Write_U32(Size, _CommandAddress + 0x4);
|
||||
return true;
|
||||
|
@ -365,7 +365,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
break;
|
||||
}
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_SEEKCONTENT: CFD %x, Addr 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position);
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_SEEKCONTENT: CFD %x, Address 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position);
|
||||
|
||||
Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4);
|
||||
return true;
|
||||
|
@ -575,7 +575,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
|
||||
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffersize: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
|
||||
|
||||
if (Loader.IsValid())
|
||||
{
|
||||
|
@ -682,7 +682,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
|
||||
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffersize: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
|
||||
|
||||
if (Loader.IsValid() && Buffer.NumberPayloadBuffer)
|
||||
{
|
||||
|
@ -777,14 +777,14 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
{
|
||||
//TODO: fixme
|
||||
// The following is obviously a hack
|
||||
// Lie to mem about loading a different ios
|
||||
// Lie to mem about loading a different IOS
|
||||
// someone with an affected game should test
|
||||
IOSv = TitleID & 0xffff;
|
||||
}
|
||||
if (!bSuccess && IOSv >= 30 && IOSv != 0xffff)
|
||||
{
|
||||
PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload ios or a title that is not available in your nand dump\n"
|
||||
"TitleID %016llx.\n Dolphin will likely hang now", TitleID);
|
||||
PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload an IOS or a title that is not available in your NAND dump\n"
|
||||
"TitleID %016llx.\n Dolphin will likely hang now.", TitleID);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -835,8 +835,8 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
|
||||
case IOCTL_ES_CHECKKOREAREGION: //note by DacoTaco : name is unknown, i just tried to name it SOMETHING
|
||||
//IOS70 has this to let system menu 4.2 check if the console is region changed. it returns -1017
|
||||
//if the IOS didn't find the korean keys and 0 if it does. 0 leads to a error 003
|
||||
WARN_LOG(WII_IPC_ES,"IOCTL_ES_CHECKKOREAREGION: Title Checked for korean Keys");
|
||||
//if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003
|
||||
WARN_LOG(WII_IPC_ES,"IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys.");
|
||||
Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT , _CommandAddress + 0x4);
|
||||
return true;
|
||||
|
||||
|
@ -952,7 +952,7 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
|
|||
{
|
||||
File::IOFile _pTMDFile(tmdPath, "wb");
|
||||
if (!_pTMDFile.WriteBytes(_pTMD, _sz))
|
||||
ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc tmd to nand");
|
||||
ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND.");
|
||||
}
|
||||
DiscIO::cUIDsys::AccessInstance().AddTitle(tmdTitleID);
|
||||
return 0;
|
||||
|
|
|
@ -136,7 +136,7 @@ bool CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress)
|
|||
if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1))
|
||||
{
|
||||
size_t numFile = FileSearch.GetFileNames().size();
|
||||
INFO_LOG(WII_IPC_FILEIO, "\t%lu Files found", (unsigned long)numFile);
|
||||
INFO_LOG(WII_IPC_FILEIO, "\t%lu files found", (unsigned long)numFile);
|
||||
|
||||
Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address);
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ bool CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress)
|
|||
fsBlocks = 0;
|
||||
iNodes = 0;
|
||||
ReturnValue = FS_RESULT_OK;
|
||||
WARN_LOG(WII_IPC_FILEIO, "FS: fsBlock failed, cannot find directoy: %s", path.c_str());
|
||||
WARN_LOG(WII_IPC_FILEIO, "FS: fsBlock failed, cannot find directory: %s", path.c_str());
|
||||
}
|
||||
|
||||
Memory::Write_U32(fsBlocks, CommandBuffer.PayloadBuffer[0].m_Address);
|
||||
|
|
|
@ -158,7 +158,7 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
|
|||
break;
|
||||
|
||||
case IOCTL_SENDCMD:
|
||||
INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD %x ipc:%08x",
|
||||
INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD %x IPC:%08x",
|
||||
Memory::Read_U32(BufferIn), _CommandAddress);
|
||||
ReturnValue = ExecuteCommand(BufferIn, BufferInSize, 0, 0, BufferOut, BufferOutSize);
|
||||
break;
|
||||
|
@ -242,7 +242,7 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtlV(u32 _CommandAddress)
|
|||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(WII_IPC_SD, "unknown SD IOCtlV command 0x%08x", CommandBuffer.Parameter);
|
||||
ERROR_LOG(WII_IPC_SD, "Unknown SD IOCtlV command 0x%08x", CommandBuffer.Parameter);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -376,7 +376,7 @@ u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInS
|
|||
{
|
||||
Memory::Write_U8((u8)buffer[i], req.addr++);
|
||||
}
|
||||
DEBUG_LOG(WII_IPC_SD, "outbuffer size %i got %i", _rwBufferSize, i);
|
||||
DEBUG_LOG(WII_IPC_SD, "Outbuffer size %i got %i", _rwBufferSize, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -178,7 +178,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::Close(u32 _CommandAddress, bool _bForc
|
|||
|
||||
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtl(u32 _CommandAddress)
|
||||
{
|
||||
//ERROR_LOG(WII_IPC_WIIMOTE, "passing ioctl to ioctlv");
|
||||
//ERROR_LOG(WII_IPC_WIIMOTE, "Passing ioctl to ioctlv");
|
||||
return IOCtlV(_CommandAddress); //hack
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
|
|||
else
|
||||
{
|
||||
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, "
|
||||
"queueing(%lu)...", (unsigned long)m_EventQueue.size());
|
||||
"queuing(%lu)...", (unsigned long)m_EventQueue.size());
|
||||
m_EventQueue.push_back(_event);
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
|||
{
|
||||
bool packet_transferred = false;
|
||||
|
||||
// check hci queue
|
||||
// check HCI queue
|
||||
if (!m_EventQueue.empty() && m_HCIEndpoint.IsValid())
|
||||
{
|
||||
// an endpoint has become available, and we have a stored response.
|
||||
|
@ -450,7 +450,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
|||
packet_transferred = true;
|
||||
}
|
||||
|
||||
// check acl queue
|
||||
// check ACL queue
|
||||
if (!m_acl_pool.IsEmpty() && m_ACLEndpoint.IsValid() && m_EventQueue.empty())
|
||||
{
|
||||
m_acl_pool.WriteToEndpoint(m_ACLEndpoint);
|
||||
|
@ -517,7 +517,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u
|
|||
}
|
||||
|
||||
_dbg_assert_msg_(WII_IPC_WIIMOTE,
|
||||
size < m_acl_pkt_size, "acl packet too large for pool");
|
||||
size < m_acl_pkt_size, "ACL packet too large for pool");
|
||||
|
||||
m_queue.push_back(Packet());
|
||||
auto& packet = m_queue.back();
|
||||
|
@ -602,7 +602,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryResponse()
|
|||
pResponse->page_scan_mode = 0;
|
||||
pResponse->clock_offset = 0x3818;
|
||||
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Event: Send Fake Inquriy of one controller");
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Event: Send Fake Inquiry of one controller");
|
||||
INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
pResponse->bdaddr.b[0], pResponse->bdaddr.b[1], pResponse->bdaddr.b[2],
|
||||
pResponse->bdaddr.b[3], pResponse->bdaddr.b[4], pResponse->bdaddr.b[5]);
|
||||
|
@ -1778,7 +1778,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBufferSize(u8* _Input)
|
|||
hci_read_buffer_size_rp Reply;
|
||||
Reply.status = 0x00;
|
||||
Reply.max_acl_size = m_acl_pkt_size;
|
||||
// Due to how the widcomm stack which nintendo uses is coded, we must never
|
||||
// Due to how the widcomm stack which Nintendo uses is coded, we must never
|
||||
// let the stack think the controller is buffering more than 10 data packets
|
||||
// - it will cause a u8 underflow and royally screw things up.
|
||||
Reply.num_acl_pkts = m_acl_pkts_num;
|
||||
|
@ -1823,7 +1823,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4F(u8* _Input,
|
|||
Reply.status = 0x00;
|
||||
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Command: CommandVendorSpecific_FC4F: (callstack WUDiRemovePatch)");
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "input (size 0x%x):", _Size);
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Input (size 0x%x):", _Size);
|
||||
|
||||
Dolphin_Debugger::PrintDataBuffer(LogTypes::WII_IPC_WIIMOTE, _Input, _Size, "Data: ");
|
||||
|
||||
|
@ -1836,7 +1836,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4C(u8* _Input,
|
|||
Reply.status = 0x00;
|
||||
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Command: CommandVendorSpecific_FC4C:");
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "input (size 0x%x):", _Size);
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Input (size 0x%x):", _Size);
|
||||
Dolphin_Debugger::PrintDataBuffer(LogTypes::WII_IPC_WIIMOTE, _Input, _Size, "Data: ");
|
||||
|
||||
SendEventCommandComplete(0xFC4C, &Reply, sizeof(hci_status_rp));
|
||||
|
@ -1862,9 +1862,9 @@ CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(const b
|
|||
return &m_WiiMotes[i];
|
||||
}
|
||||
|
||||
ERROR_LOG(WII_IPC_WIIMOTE,"Cant find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ERROR_LOG(WII_IPC_WIIMOTE,"Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
_rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]);
|
||||
PanicAlertT("Cant find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
PanicAlertT("Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
_rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1877,8 +1877,8 @@ CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(u16 _Co
|
|||
return &m_WiiMotes[i];
|
||||
}
|
||||
|
||||
ERROR_LOG(WII_IPC_WIIMOTE, "Cant find WiiMote by connection handle %02x", _ConnectionHandle);
|
||||
PanicAlertT("Cant find WiiMote by connection handle %02x", _ConnectionHandle);
|
||||
ERROR_LOG(WII_IPC_WIIMOTE, "Can't find WiiMote by connection handle %02x", _ConnectionHandle);
|
||||
PanicAlertT("Can't find WiiMote by connection handle %02x", _ConnectionHandle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -227,7 +227,7 @@ u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {
|
|||
0x55, // Multiply
|
||||
0x57, // Add
|
||||
0x00, // Separator
|
||||
0x56, // Substract
|
||||
0x56, // Subtract
|
||||
0x63, // Decimal
|
||||
0x54, // Divide
|
||||
// F1 -> F12
|
||||
|
|
|
@ -309,7 +309,7 @@ void CWII_IPC_HLE_WiiMote::ExecuteL2capCmd(u8* _pData, u32 _Size)
|
|||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(WII_IPC_WIIMOTE, "channel 0x04%x has unknown PSM %x", pHeader->dcid, rChannel.PSM);
|
||||
ERROR_LOG(WII_IPC_WIIMOTE, "Channel 0x04%x has unknown PSM %x", pHeader->dcid, rChannel.PSM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -751,8 +751,8 @@ void CWII_IPC_HLE_WiiMote::SDPSendServiceAttributeResponse(u16 cid, u16 Transact
|
|||
{
|
||||
if (ServiceHandle != 0x10000)
|
||||
{
|
||||
ERROR_LOG(WII_IPC_WIIMOTE, "unknown service handle %x" , ServiceHandle);
|
||||
PanicAlert("unknown service handle %x" , ServiceHandle);
|
||||
ERROR_LOG(WII_IPC_WIIMOTE, "Unknown service handle %x" , ServiceHandle);
|
||||
PanicAlert("Unknown service handle %x" , ServiceHandle);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -271,6 +271,16 @@ bool NetPlay::StopGame()
|
|||
return true;
|
||||
}
|
||||
|
||||
void NetPlay::SetMemcardWriteEnabled(bool enabled)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
||||
|
||||
if (m_is_running)
|
||||
{
|
||||
Core::g_CoreStartupParameter.bEnableMemcardSaving = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
// called from ---CPU--- thread
|
||||
u8 NetPlay::GetPadNum(u8 numPAD)
|
||||
{
|
||||
|
|
|
@ -111,6 +111,7 @@ public:
|
|||
virtual bool StartGame(const std::string &path);
|
||||
virtual bool StopGame();
|
||||
|
||||
virtual void SetMemcardWriteEnabled(bool enabled);
|
||||
//void PushPadStates(unsigned int count);
|
||||
|
||||
u8 GetPadNum(u8 numPAD);
|
||||
|
|
|
@ -52,7 +52,7 @@ void NetPlayServer::ThreadFunc()
|
|||
// update pings every so many seconds
|
||||
if ((m_ping_timer.GetTimeElapsed() > (10 * 1000)) || m_update_pings)
|
||||
{
|
||||
//PanicAlertT("sending pings");
|
||||
//PanicAlertT("Sending pings");
|
||||
|
||||
m_ping_key = Common::Timer::GetTimeMs();
|
||||
|
||||
|
@ -487,7 +487,7 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
|
|||
|
||||
if (m_ping_key == ping_key)
|
||||
{
|
||||
//PanicAlertT("good pong");
|
||||
//PanicAlertT("Good pong");
|
||||
player.ping = ping;
|
||||
}
|
||||
m_dialog->Update();
|
||||
|
|
|
@ -306,7 +306,7 @@ void Interpreter::unknown_instruction(UGeckoInstruction _inst)
|
|||
DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256);
|
||||
NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm);
|
||||
Dolphin_Debugger::PrintCallstack();
|
||||
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
|
||||
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -679,7 +679,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
|||
{
|
||||
char ppcInst[256];
|
||||
DisassembleGekko(ops[i].inst.hex, em_address, ppcInst, 256);
|
||||
NOTICE_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst);
|
||||
NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppcInst);
|
||||
}
|
||||
#endif
|
||||
if (js.skipnext) {
|
||||
|
|
|
@ -388,7 +388,7 @@ void RegCache::Flush(FlushMode mode)
|
|||
{
|
||||
if (locks[i])
|
||||
{
|
||||
PanicAlert("Somebody forgot to unlock PPC reg %i.", i);
|
||||
PanicAlert("Someone forgot to unlock PPC reg %i.", i);
|
||||
}
|
||||
if (regs[i].away)
|
||||
{
|
||||
|
|
|
@ -125,7 +125,7 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info)
|
|||
// It's a write. Yay. Remember that we don't have to be super efficient since it's "just" a
|
||||
// hardware access - we can take shortcuts.
|
||||
//if (emAddress == 0xCC008000)
|
||||
// PanicAlert("caught a fifo write");
|
||||
// PanicAlert("Caught a FIFO write");
|
||||
CMP(32, R(addrReg), Imm32(0xCC008000));
|
||||
FixupBranch skip_fast = J_CC(CC_NE, false);
|
||||
MOV(32, R(ABI_PARAM1), R((X64Reg)dataReg));
|
||||
|
@ -215,7 +215,7 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void
|
|||
emitter.CALL((void *)trampoline);
|
||||
emitter.NOP((int)info.instructionSize - 3);
|
||||
if (info.instructionSize < 3)
|
||||
PanicAlert("instruction too small");
|
||||
PanicAlert("Instruction too small");
|
||||
// We entered here with a BSWAP-ed EAX. We'll have to swap it back.
|
||||
ctx->Rax = Common::swap32((u32)ctx->Rax);
|
||||
return codePtr - 2;
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace JitInterface
|
|||
File::IOFile f(filename, "w");
|
||||
if (!f)
|
||||
{
|
||||
PanicAlert("failed to open %s", filename);
|
||||
PanicAlert("Failed to open %s", filename);
|
||||
return;
|
||||
}
|
||||
fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
|
||||
|
|
|
@ -290,7 +290,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa,
|
|||
int capacity_of_merged_addresses, int& size_of_merged_addresses)
|
||||
{
|
||||
if (capacity_of_merged_addresses < FUNCTION_FOLLOWING_THRESHOLD) {
|
||||
PanicAlert("capacity of merged_addresses is too small!");
|
||||
PanicAlert("Capacity of merged_addresses is too small!");
|
||||
}
|
||||
std::fill_n(merged_addresses, capacity_of_merged_addresses, 0);
|
||||
merged_addresses[0] = address;
|
||||
|
@ -697,7 +697,7 @@ void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db)
|
|||
{
|
||||
if (iter->second.address == 4)
|
||||
{
|
||||
WARN_LOG(OSHLE, "weird function");
|
||||
WARN_LOG(OSHLE, "Weird function");
|
||||
continue;
|
||||
}
|
||||
AnalyzeFunction2(&(iter->second));
|
||||
|
|
|
@ -93,7 +93,7 @@ bool SetupScrub(const char* filename, int block_size)
|
|||
|
||||
if (CLUSTER_SIZE % m_BlockSize != 0)
|
||||
{
|
||||
ERROR_LOG(DISCIO, "block size %i is not a factor of 0x8000, scrubbing not possible", m_BlockSize);
|
||||
ERROR_LOG(DISCIO, "Block size %i is not a factor of 0x8000, scrubbing not possible", m_BlockSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ bool SetupScrub(const char* filename, int block_size)
|
|||
|
||||
// Warn if not DVD5 or DVD9 size
|
||||
if (numClusters != 0x23048 && numClusters != 0x46090)
|
||||
WARN_LOG(DISCIO, "%s is not a standard sized wii disc! (%x blocks)", filename, numClusters);
|
||||
WARN_LOG(DISCIO, "%s is not a standard sized Wii disc! (%x blocks)", filename, numClusters);
|
||||
|
||||
// Table of free blocks
|
||||
m_FreeTable = new u8[numClusters];
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
<string>${OSX_MIN_VERSION}</string>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
|
|
@ -170,8 +170,12 @@ void CARCodeAddEdit::UpdateTextCtrl(ActionReplay::ARCode arCode)
|
|||
EditCheatCode->Clear();
|
||||
|
||||
if (arCode.name != "")
|
||||
{
|
||||
for (u32 i = 0; i < arCode.ops.size(); i++)
|
||||
EditCheatCode->AppendText(wxString::Format(wxT("%08X %08X\n"), arCode.ops.at(i).cmd_addr, arCode.ops.at(i).value));
|
||||
}
|
||||
else
|
||||
{
|
||||
EditCheatCode->SetValue(_("Insert Encrypted or Decrypted code here..."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -298,10 +298,11 @@ void wxCheatsWindow::OnEvent_CheatsList_ItemSelected(wxCommandEvent& WXUNUSED (e
|
|||
sprintf(numcodes, "Number of Codes: %lu", (unsigned long)code.ops.size());
|
||||
m_Label_NumCodes->SetLabel(StrToWxStr(numcodes));
|
||||
m_ListBox_CodesList->Clear();
|
||||
|
||||
for (size_t j = 0; j < code.ops.size(); j++)
|
||||
{
|
||||
char text2[CHAR_MAX];
|
||||
char* ops = text2;
|
||||
char* ops = text2;
|
||||
sprintf(ops, "%08x %08x", code.ops[j].cmd_addr, code.ops[j].value);
|
||||
m_ListBox_CodesList->Append(StrToWxStr(ops));
|
||||
}
|
||||
|
@ -332,7 +333,7 @@ void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
|
|||
// Apply Gecko Code changes
|
||||
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
|
||||
|
||||
// save gameini, with changed gecko codes
|
||||
// Save gameini, with changed gecko codes
|
||||
if (m_gameini_path.size())
|
||||
{
|
||||
Gecko::SaveCodes(m_gameini, m_geckocode_panel->GetCodes());
|
||||
|
@ -409,7 +410,7 @@ void CheatSearchTab::FilterCheatSearchResults(wxCommandEvent&)
|
|||
filtered_results.reserve(search_results.size());
|
||||
|
||||
|
||||
// determine the selected filter
|
||||
// Determine the selected filter
|
||||
// 1 : equal
|
||||
// 2 : greater-than
|
||||
// 4 : less-than
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <string> // System
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <wx/spinbutt.h>
|
||||
|
||||
#include "Common.h"
|
||||
|
@ -43,14 +44,6 @@
|
|||
#include "Main.h"
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <tr1/functional>
|
||||
using std::tr1::function;
|
||||
#else
|
||||
#include <functional>
|
||||
using std::function;
|
||||
#endif
|
||||
|
||||
#define TEXT_BOX(page, text) new wxStaticText(page, wxID_ANY, text, wxDefaultPosition, wxDefaultSize)
|
||||
|
||||
struct CPUCore
|
||||
|
@ -59,12 +52,12 @@ struct CPUCore
|
|||
const char *name;
|
||||
};
|
||||
const CPUCore CPUCores[] = {
|
||||
{0, "Interpreter (VERY slow)"},
|
||||
{0, wxTRANSLATE("Interpreter (VERY slow)")},
|
||||
#ifdef _M_ARM
|
||||
{3, "Arm JIT (experimental)"},
|
||||
{3, wxTRANSLATE("Arm JIT (experimental)")},
|
||||
#else
|
||||
{1, "JIT Recompiler (recommended)"},
|
||||
{2, "JITIL experimental recompiler"},
|
||||
{1, wxTRANSLATE("JIT Recompiler (recommended)")},
|
||||
{2, wxTRANSLATE("JITIL experimental recompiler")},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -268,7 +261,7 @@ void CConfigMain::InitializeGUILists()
|
|||
|
||||
// Emulator Engine
|
||||
for (unsigned int a = 0; a < (sizeof(CPUCores) / sizeof(CPUCore)); ++a)
|
||||
arrayStringFor_CPUEngine.Add(_(CPUCores[a].name));
|
||||
arrayStringFor_CPUEngine.Add(wxGetTranslation(CPUCores[a].name));
|
||||
|
||||
// DSP Engine
|
||||
arrayStringFor_DSPEngine.Add(_("DSP HLE emulation (fast)"));
|
||||
|
@ -515,7 +508,7 @@ void CConfigMain::InitializeGUITooltips()
|
|||
InterfaceLang->SetToolTip(_("Change the language of the user interface.\nRequires restart."));
|
||||
|
||||
// Audio tooltips
|
||||
DSPThread->SetToolTip(_("Run DSP LLE on a dedicated thread (not recommended)."));
|
||||
DSPThread->SetToolTip(_("Run DSP HLE and LLE on a dedicated thread (not recommended: might cause audio glitches with HLE and freezes with LLE)."));
|
||||
BackendSelection->SetToolTip(_("Changing this will have no effect while the emulator is running!"));
|
||||
|
||||
// Gamecube - Devices
|
||||
|
@ -624,16 +617,17 @@ void CConfigMain::CreateGUIControls()
|
|||
SplitPath(filename, NULL, &name, &ext);
|
||||
|
||||
name += ext;
|
||||
if (-1 == theme_selection->FindString(name))
|
||||
theme_selection->Append(name);
|
||||
auto const wxname = StrToWxStr(name);
|
||||
if (-1 == theme_selection->FindString(wxname))
|
||||
theme_selection->Append(wxname);
|
||||
});
|
||||
|
||||
theme_selection->SetStringSelection(SConfig::GetInstance().m_LocalCoreStartupParameter.theme_name);
|
||||
theme_selection->SetStringSelection(StrToWxStr(SConfig::GetInstance().m_LocalCoreStartupParameter.theme_name));
|
||||
|
||||
// std::function = avoid error on msvc
|
||||
theme_selection->Bind(wxEVT_COMMAND_CHOICE_SELECTED, function<void(wxEvent&)>([theme_selection](wxEvent&)
|
||||
theme_selection->Bind(wxEVT_COMMAND_CHOICE_SELECTED, std::function<void(wxEvent&)>([theme_selection](wxEvent&)
|
||||
{
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.theme_name = theme_selection->GetStringSelection();
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.theme_name = WxStrToStr(theme_selection->GetStringSelection());
|
||||
main_frame->InitBitmaps();
|
||||
main_frame->UpdateGameList();
|
||||
}));
|
||||
|
@ -657,7 +651,7 @@ void CConfigMain::CreateGUIControls()
|
|||
// Audio page
|
||||
DSPEngine = new wxRadioBox(AudioPage, ID_DSPENGINE, _("DSP Emulator Engine"),
|
||||
wxDefaultPosition, wxDefaultSize, arrayStringFor_DSPEngine, 0, wxRA_SPECIFY_ROWS);
|
||||
DSPThread = new wxCheckBox(AudioPage, ID_DSPTHREAD, _("DSP LLE on Thread"));
|
||||
DSPThread = new wxCheckBox(AudioPage, ID_DSPTHREAD, _("DSP on Dedicated Thread"));
|
||||
DumpAudio = new wxCheckBox(AudioPage, ID_DUMP_AUDIO, _("Dump Audio"),
|
||||
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
DPL2Decoder = new wxCheckBox(AudioPage, ID_DPL2DECODER, _("Dolby Pro Logic II decoder"));
|
||||
|
@ -976,7 +970,9 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event)
|
|||
VolumeSlider->Enable(SupportsVolumeChanges(WxStrToStr(BackendSelection->GetStringSelection())));
|
||||
Latency->Enable(WxStrToStr(BackendSelection->GetStringSelection()) == BACKEND_OPENAL);
|
||||
DPL2Decoder->Enable(WxStrToStr(BackendSelection->GetStringSelection()) == BACKEND_OPENAL);
|
||||
SConfig::GetInstance().sBackend = WxStrToStr(BackendSelection->GetStringSelection());
|
||||
// Don't save the translated BACKEND_NULLSOUND string
|
||||
SConfig::GetInstance().sBackend = BackendSelection->GetSelection() ?
|
||||
WxStrToStr(BackendSelection->GetStringSelection()) : BACKEND_NULLSOUND;
|
||||
AudioCommon::UpdateSoundStream();
|
||||
break;
|
||||
|
||||
|
@ -997,8 +993,8 @@ void CConfigMain::AddAudioBackends()
|
|||
for (std::vector<std::string>::const_iterator iter = backends.begin();
|
||||
iter != backends.end(); ++iter)
|
||||
{
|
||||
BackendSelection->Append(StrToWxStr(*iter));
|
||||
int num = BackendSelection->\
|
||||
BackendSelection->Append(wxGetTranslation(StrToWxStr(*iter)));
|
||||
int num = BackendSelection->
|
||||
FindString(StrToWxStr(SConfig::GetInstance().sBackend));
|
||||
BackendSelection->SetSelection(num);
|
||||
}
|
||||
|
@ -1239,7 +1235,9 @@ void CConfigMain::AddRemoveISOPaths(wxCommandEvent& event)
|
|||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
if (ISOPaths->FindString(dialog.GetPath()) != -1)
|
||||
{
|
||||
wxMessageBox(_("The chosen directory is already in the list"), _("Error"), wxOK);
|
||||
}
|
||||
else
|
||||
{
|
||||
bRefreshList = true;
|
||||
|
|
|
@ -47,10 +47,12 @@ void BreakPointDlg::OnOK(wxCommandEvent& event)
|
|||
{
|
||||
PowerPC::breakpoints.Add(Address);
|
||||
Parent->NotifyUpdate();
|
||||
Close();
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("The address %s is invalid.", WxStrToStr(AddressString).c_str());
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
|
|
@ -40,10 +40,10 @@ void CBreakPointView::Update()
|
|||
InsertColumn(0, wxT("Active"));
|
||||
InsertColumn(1, wxT("Type"));
|
||||
InsertColumn(2, wxT("Function"));
|
||||
InsertColumn(3, wxT("Address"));
|
||||
InsertColumn(4, wxT("Flags"));
|
||||
InsertColumn(3, wxT("Address"));
|
||||
InsertColumn(4, wxT("Flags"));
|
||||
|
||||
char szBuffer[64];
|
||||
char szBuffer[64];
|
||||
const BreakPoints::TBreakPoints& rBreakPoints = PowerPC::breakpoints.GetBreakPoints();
|
||||
for (size_t i = 0; i < rBreakPoints.size(); i++)
|
||||
{
|
||||
|
@ -63,11 +63,11 @@ void CBreakPointView::Update()
|
|||
SetItem(Item, 2, temp);
|
||||
}
|
||||
|
||||
sprintf(szBuffer, "%08x", rBP.iAddress);
|
||||
temp = StrToWxStr(szBuffer);
|
||||
sprintf(szBuffer, "%08x", rBP.iAddress);
|
||||
temp = StrToWxStr(szBuffer);
|
||||
SetItem(Item, 3, temp);
|
||||
|
||||
SetItemData(Item, rBP.iAddress);
|
||||
SetItemData(Item, rBP.iAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,12 +108,12 @@ void CBreakPointView::Update()
|
|||
|
||||
void CBreakPointView::DeleteCurrentSelection()
|
||||
{
|
||||
int Item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
if (Item >= 0)
|
||||
{
|
||||
u32 Address = (u32)GetItemData(Item);
|
||||
PowerPC::breakpoints.Remove(Address);
|
||||
PowerPC::memchecks.Remove(Address);
|
||||
int Item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
if (Item >= 0)
|
||||
{
|
||||
u32 Address = (u32)GetItemData(Item);
|
||||
PowerPC::breakpoints.Remove(Address);
|
||||
PowerPC::memchecks.Remove(Address);
|
||||
Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,20 +62,20 @@ END_EVENT_TABLE()
|
|||
CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB *symboldb,
|
||||
wxWindow* parent, wxWindowID Id)
|
||||
: wxControl(parent, Id),
|
||||
debugger(debuginterface),
|
||||
debugger(debuginterface),
|
||||
symbol_db(symboldb),
|
||||
plain(false),
|
||||
curAddress(debuginterface->getPC()),
|
||||
align(debuginterface->getInstructionSize(0)),
|
||||
rowHeight(13),
|
||||
selection(0),
|
||||
oldSelection(0),
|
||||
selectionChanged(false),
|
||||
selecting(false),
|
||||
hasFocus(false),
|
||||
showHex(false),
|
||||
lx(-1),
|
||||
ly(-1)
|
||||
rowHeight(13),
|
||||
selection(0),
|
||||
oldSelection(0),
|
||||
selectionChanged(false),
|
||||
selecting(false),
|
||||
hasFocus(false),
|
||||
showHex(false),
|
||||
lx(-1),
|
||||
ly(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,9 @@ void CCodeView::OnMouseDown(wxMouseEvent& event)
|
|||
Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleBreakpoint(YToAddress(y));
|
||||
}
|
||||
|
||||
event.Skip(true);
|
||||
}
|
||||
|
@ -133,7 +135,9 @@ void CCodeView::OnMouseMove(wxMouseEvent& event)
|
|||
Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnMouseDown(event);
|
||||
}
|
||||
}
|
||||
|
||||
event.Skip(true);
|
||||
|
@ -176,14 +180,17 @@ u32 CCodeView::AddrToBranch(u32 addr)
|
|||
void CCodeView::InsertBlrNop(int Blr)
|
||||
{
|
||||
// Check if this address has been modified
|
||||
int find = -1;
|
||||
int find = -1;
|
||||
for(u32 i = 0; i < BlrList.size(); i++)
|
||||
{
|
||||
if(BlrList.at(i).Address == selection)
|
||||
{ find = i; break; }
|
||||
{
|
||||
find = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the old value
|
||||
// Save the old value
|
||||
if (find >= 0)
|
||||
{
|
||||
debugger->writeExtraMemory(0, BlrList.at(find).OldValue, selection);
|
||||
|
@ -196,11 +203,11 @@ void CCodeView::InsertBlrNop(int Blr)
|
|||
Temp.OldValue = debugger->readMemory(selection);
|
||||
BlrList.push_back(Temp);
|
||||
if (Blr == 0)
|
||||
debugger->insertBLR(selection, 0x4e800020);
|
||||
debugger->insertBLR(selection, 0x4e800020);
|
||||
else
|
||||
debugger->insertBLR(selection, 0x60000000);
|
||||
debugger->insertBLR(selection, 0x60000000);
|
||||
}
|
||||
Refresh();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
||||
|
@ -211,14 +218,14 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
|||
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_GOTOINMEMVIEW:
|
||||
// CMemoryDlg::Goto(selection);
|
||||
break;
|
||||
case IDM_GOTOINMEMVIEW:
|
||||
// CMemoryDlg::Goto(selection);
|
||||
break;
|
||||
|
||||
#if wxUSE_CLIPBOARD
|
||||
case IDM_COPYADDRESS:
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format(_T("%08x"), selection)));
|
||||
break;
|
||||
case IDM_COPYADDRESS:
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format(_T("%08x"), selection)));
|
||||
break;
|
||||
|
||||
case IDM_COPYCODE:
|
||||
{
|
||||
|
@ -228,13 +235,13 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
|||
}
|
||||
break;
|
||||
|
||||
case IDM_COPYHEX:
|
||||
{
|
||||
char temp[24];
|
||||
sprintf(temp, "%08x", debugger->readInstruction(selection));
|
||||
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
|
||||
}
|
||||
break;
|
||||
case IDM_COPYHEX:
|
||||
{
|
||||
char temp[24];
|
||||
sprintf(temp, "%08x", debugger->readInstruction(selection));
|
||||
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case IDM_COPYFUNCTION:
|
||||
|
@ -259,11 +266,11 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case IDM_RUNTOHERE:
|
||||
debugger->setBreakpoint(selection);
|
||||
debugger->runToBreakpoint();
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_RUNTOHERE:
|
||||
debugger->setBreakpoint(selection);
|
||||
debugger->runToBreakpoint();
|
||||
Refresh();
|
||||
break;
|
||||
|
||||
// Insert blr or restore old value
|
||||
case IDM_INSERTBLR:
|
||||
|
@ -275,9 +282,9 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
|||
Refresh();
|
||||
break;
|
||||
|
||||
case IDM_JITRESULTS:
|
||||
case IDM_JITRESULTS:
|
||||
debugger->showJitResults(selection);
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_FOLLOWBRANCH:
|
||||
{
|
||||
|
@ -366,7 +373,7 @@ void CCodeView::OnPaint(wxPaintEvent& event)
|
|||
dc.GetTextExtent(_T("0WJyq"),&w,&h);
|
||||
|
||||
if (h > rowHeight)
|
||||
rowHeight = h;
|
||||
rowHeight = h;
|
||||
|
||||
dc.GetTextExtent(_T("W"),&w,&h);
|
||||
int charWidth = w;
|
||||
|
@ -507,7 +514,8 @@ void CCodeView::OnPaint(wxPaintEvent& event)
|
|||
strcpy(desc, debugger->getDescription(address).c_str());
|
||||
}
|
||||
|
||||
if (!plain) {
|
||||
if (!plain)
|
||||
{
|
||||
dc.SetTextForeground(_T("#0000FF")); // blue
|
||||
|
||||
//char temp[256];
|
||||
|
@ -535,11 +543,11 @@ void CCodeView::OnPaint(wxPaintEvent& event)
|
|||
|
||||
for (int i = 0; i < numBranches; i++)
|
||||
{
|
||||
int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8;
|
||||
_MoveTo(x-2, branches[i].src);
|
||||
int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8;
|
||||
_MoveTo(x-2, branches[i].src);
|
||||
|
||||
if (branches[i].dst < rc.height + 400 && branches[i].dst > -400)
|
||||
{
|
||||
{
|
||||
_LineTo(dc, x+2, branches[i].src);
|
||||
_LineTo(dc, x+2, branches[i].dst);
|
||||
_LineTo(dc, x-4, branches[i].dst);
|
||||
|
@ -547,7 +555,7 @@ void CCodeView::OnPaint(wxPaintEvent& event)
|
|||
_MoveTo(x, branches[i].dst - 4);
|
||||
_LineTo(dc, x-4, branches[i].dst);
|
||||
_LineTo(dc, x+1, branches[i].dst+5);
|
||||
}
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// This can be re-enabled when there is a scrollbar or
|
||||
|
|
|
@ -138,16 +138,16 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event)
|
|||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_NOTIFYMAPLOADED:
|
||||
NotifyMapLoaded();
|
||||
case IDM_NOTIFYMAPLOADED:
|
||||
NotifyMapLoaded();
|
||||
if (m_BreakpointWindow) m_BreakpointWindow->NotifyUpdate();
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_UPDATEDISASMDIALOG:
|
||||
Update();
|
||||
case IDM_UPDATEDISASMDIALOG:
|
||||
Update();
|
||||
if (codeview) codeview->Center(PC);
|
||||
if (m_RegisterWindow) m_RegisterWindow->NotifyUpdate();
|
||||
break;
|
||||
if (m_RegisterWindow) m_RegisterWindow->NotifyUpdate();
|
||||
break;
|
||||
|
||||
case IDM_UPDATEBREAKPOINTS:
|
||||
Update();
|
||||
|
@ -161,31 +161,31 @@ void CCodeWindow::OnCodeStep(wxCommandEvent& event)
|
|||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_STEP:
|
||||
case IDM_STEP:
|
||||
SingleStep();
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_STEPOVER:
|
||||
case IDM_STEPOVER:
|
||||
StepOver();
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_TOGGLE_BREAKPOINT:
|
||||
ToggleBreakpoint();
|
||||
break;
|
||||
|
||||
case IDM_SKIP:
|
||||
PC += 4;
|
||||
Update();
|
||||
break;
|
||||
case IDM_SKIP:
|
||||
PC += 4;
|
||||
Update();
|
||||
break;
|
||||
|
||||
case IDM_SETPC:
|
||||
PC = codeview->GetSelection();
|
||||
Update();
|
||||
break;
|
||||
case IDM_SETPC:
|
||||
PC = codeview->GetSelection();
|
||||
Update();
|
||||
break;
|
||||
|
||||
case IDM_GOTOPC:
|
||||
JumpToAddress(PC);
|
||||
break;
|
||||
case IDM_GOTOPC:
|
||||
JumpToAddress(PC);
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateButtonStates();
|
||||
|
@ -227,7 +227,7 @@ void CCodeWindow::OnCallstackListChange(wxCommandEvent& event)
|
|||
{
|
||||
int index = callstack->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
{
|
||||
u32 address = (u32)(u64)(callstack->GetClientData(index));
|
||||
if (address)
|
||||
JumpToAddress(address);
|
||||
|
@ -238,7 +238,7 @@ void CCodeWindow::OnCallersListChange(wxCommandEvent& event)
|
|||
{
|
||||
int index = callers->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
{
|
||||
u32 address = (u32)(u64)(callers->GetClientData(index));
|
||||
if (address)
|
||||
JumpToAddress(address);
|
||||
|
@ -249,7 +249,7 @@ void CCodeWindow::OnCallsListChange(wxCommandEvent& event)
|
|||
{
|
||||
int index = calls->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
{
|
||||
u32 address = (u32)(u64)(calls->GetClientData(index));
|
||||
if (address)
|
||||
JumpToAddress(address);
|
||||
|
@ -283,7 +283,9 @@ void CCodeWindow::StepOver()
|
|||
Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleStep();
|
||||
}
|
||||
|
||||
UpdateButtonStates();
|
||||
// Update all toolbars in the aui manager
|
||||
|
@ -307,12 +309,13 @@ void CCodeWindow::UpdateLists()
|
|||
Symbol *symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
if (!symbol)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < (int)symbol->callers.size(); i++)
|
||||
{
|
||||
u32 caller_addr = symbol->callers[i].callAddress;
|
||||
Symbol *caller_symbol = g_symbolDB.GetSymbolFromAddr(caller_addr);
|
||||
if (caller_symbol)
|
||||
{
|
||||
{
|
||||
int idx = callers->Append(StrToWxStr(StringFromFormat
|
||||
("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str()));
|
||||
callers->SetClientData(idx, (void*)(u64)caller_addr);
|
||||
|
@ -325,7 +328,7 @@ void CCodeWindow::UpdateLists()
|
|||
u32 call_addr = symbol->calls[i].function;
|
||||
Symbol *call_symbol = g_symbolDB.GetSymbolFromAddr(call_addr);
|
||||
if (call_symbol)
|
||||
{
|
||||
{
|
||||
int idx = calls->Append(StrToWxStr(StringFromFormat
|
||||
("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str()));
|
||||
calls->SetClientData(idx, (void*)(u64)call_addr);
|
||||
|
@ -354,8 +357,7 @@ void CCodeWindow::UpdateCallstack()
|
|||
}
|
||||
|
||||
// Create CPU Mode menus
|
||||
void CCodeWindow::CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParameter,
|
||||
wxMenuBar *pMenuBar)
|
||||
void CCodeWindow::CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParameter, wxMenuBar *pMenuBar)
|
||||
{
|
||||
// CPU Mode
|
||||
wxMenu* pCoreMenu = new wxMenu;
|
||||
|
@ -386,7 +388,7 @@ void CCodeWindow::CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParam
|
|||
_("Turn off all JIT functions, but still use the JIT core from Jit.cpp"),
|
||||
wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITLSOFF, _("&JIT LoadStore off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITLSLBZXOFF, _(" &JIT LoadStore lbzx off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITLSLXZOFF, _(" &JIT LoadStore lXz off"),
|
||||
|
@ -394,17 +396,17 @@ void CCodeWindow::CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParam
|
|||
pCoreMenu->Append(IDM_JITLSLWZOFF, _("&JIT LoadStore lwz off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITLSFOFF, _("&JIT LoadStore Floating off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITLSPOFF, _("&JIT LoadStore Paired off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITFPOFF, _("&JIT FloatingPoint off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITIOFF, _("&JIT Integer off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITPOFF, _("&JIT Paired off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
pCoreMenu->Append(IDM_JITSROFF, _("&JIT SystemRegisters off"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
|
||||
pMenuBar->Append(pCoreMenu, _("&JIT"));
|
||||
|
||||
|
@ -448,46 +450,46 @@ void CCodeWindow::OnCPUMode(wxCommandEvent& event)
|
|||
{
|
||||
case IDM_INTERPRETER:
|
||||
PowerPC::SetMode(UseInterpreter() ? PowerPC::MODE_INTERPRETER : PowerPC::MODE_JIT);
|
||||
break;
|
||||
break;
|
||||
case IDM_BOOTTOPAUSE:
|
||||
bBootToPause = !bBootToPause;
|
||||
return;
|
||||
return;
|
||||
case IDM_AUTOMATICSTART:
|
||||
bAutomaticStart = !bAutomaticStart;
|
||||
return;
|
||||
return;
|
||||
case IDM_JITOFF:
|
||||
Core::g_CoreStartupParameter.bJITOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITLSOFF:
|
||||
Core::g_CoreStartupParameter.bJITLoadStoreOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITLSLXZOFF:
|
||||
Core::g_CoreStartupParameter.bJITLoadStorelXzOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITLSLWZOFF:
|
||||
Core::g_CoreStartupParameter.bJITLoadStorelwzOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITLSLBZXOFF:
|
||||
Core::g_CoreStartupParameter.bJITLoadStorelbzxOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITLSFOFF:
|
||||
Core::g_CoreStartupParameter.bJITLoadStoreFloatingOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITLSPOFF:
|
||||
Core::g_CoreStartupParameter.bJITLoadStorePairedOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITFPOFF:
|
||||
Core::g_CoreStartupParameter.bJITFloatingPointOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITIOFF:
|
||||
Core::g_CoreStartupParameter.bJITIntegerOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITPOFF:
|
||||
Core::g_CoreStartupParameter.bJITPairedOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
case IDM_JITSROFF:
|
||||
Core::g_CoreStartupParameter.bJITSystemRegistersOff = event.IsChecked();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the JIT cache to enable these changes
|
||||
|
@ -503,22 +505,22 @@ void CCodeWindow::OnJitMenu(wxCommandEvent& event)
|
|||
{
|
||||
case IDM_LOGINSTRUCTIONS:
|
||||
PPCTables::LogCompiledInstructions();
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_CLEARCODECACHE:
|
||||
JitInterface::ClearCache();
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_SEARCHINSTRUCTION:
|
||||
{
|
||||
wxString str;
|
||||
str = wxGetTextFromUser(_T(""), wxT("Op?"), wxEmptyString, this);
|
||||
for (u32 addr = 0x80000000; addr < 0x80100000; addr += 4)
|
||||
{
|
||||
{
|
||||
const char *name = PPCTables::GetInstructionName(Memory::ReadUnchecked_U32(addr));
|
||||
auto const wx_name = WxStrToStr(str);
|
||||
if (name && (wx_name == name))
|
||||
{
|
||||
{
|
||||
NOTICE_LOG(POWERPC, "Found %s at %08x", wx_name.c_str(), addr);
|
||||
}
|
||||
}
|
||||
|
@ -575,10 +577,10 @@ void CCodeWindow::PopulateToolbar(wxAuiToolBar* toolBar)
|
|||
|
||||
toolBar->SetToolBitmapSize(wxSize(w, h));
|
||||
toolBar->AddTool(IDM_STEP, _("Step"), m_Bitmaps[Toolbar_Step]);
|
||||
toolBar->AddTool(IDM_STEPOVER, _("Step Over"), m_Bitmaps[Toolbar_StepOver]);
|
||||
toolBar->AddTool(IDM_STEPOVER, _("Step Over"), m_Bitmaps[Toolbar_StepOver]);
|
||||
toolBar->AddTool(IDM_SKIP, _("Skip"), m_Bitmaps[Toolbar_Skip]);
|
||||
toolBar->AddSeparator();
|
||||
toolBar->AddTool(IDM_GOTOPC, _("Show PC"), m_Bitmaps[Toolbar_GotoPC]);
|
||||
toolBar->AddTool(IDM_GOTOPC, _("Show PC"), m_Bitmaps[Toolbar_GotoPC]);
|
||||
toolBar->AddTool(IDM_SETPC, _("Set PC"), m_Bitmaps[Toolbar_SetPC]);
|
||||
toolBar->AddSeparator();
|
||||
toolBar->AddControl(new wxTextCtrl(toolBar, IDM_ADDRBOX, _T("")));
|
||||
|
|
|
@ -36,13 +36,13 @@ BEGIN_EVENT_TABLE(DSPDebuggerLLE, wxPanel)
|
|||
EVT_CLOSE(DSPDebuggerLLE::OnClose)
|
||||
EVT_MENU_RANGE(ID_RUNTOOL, ID_SHOWPCTOOL, DSPDebuggerLLE::OnChangeState)
|
||||
EVT_TEXT_ENTER(ID_ADDRBOX, DSPDebuggerLLE::OnAddrBoxChange)
|
||||
EVT_LISTBOX(ID_SYMBOLLIST, DSPDebuggerLLE::OnSymbolListChange)
|
||||
EVT_LISTBOX(ID_SYMBOLLIST, DSPDebuggerLLE::OnSymbolListChange)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
|
||||
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize,
|
||||
wxTAB_TRAVERSAL, _("DSP LLE Debugger"))
|
||||
wxTAB_TRAVERSAL, _("DSP LLE Debugger"))
|
||||
, m_CachedStepCounter(-1)
|
||||
{
|
||||
m_DebuggerFrame = this;
|
||||
|
@ -184,14 +184,14 @@ void DSPDebuggerLLE::FocusOnPC()
|
|||
void DSPDebuggerLLE::UpdateState()
|
||||
{
|
||||
if (DSPCore_GetState() == DSPCORE_RUNNING)
|
||||
{
|
||||
{
|
||||
m_Toolbar->SetToolLabel(ID_RUNTOOL, wxT("Pause"));
|
||||
m_Toolbar->SetToolBitmap(ID_RUNTOOL,
|
||||
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10,10)));
|
||||
m_Toolbar->EnableTool(ID_STEPTOOL, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
else
|
||||
{
|
||||
m_Toolbar->SetToolLabel(ID_RUNTOOL, wxT("Run"));
|
||||
m_Toolbar->SetToolBitmap(ID_RUNTOOL,
|
||||
wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, wxSize(10,10)));
|
||||
|
|
|
@ -79,9 +79,10 @@ void GFXDebuggerPanel::SaveSettings() const
|
|||
|
||||
// TODO: make this work when we close the entire program too, currently on total close we get
|
||||
// weird values, perhaps because of some conflict with the rendering window
|
||||
|
||||
// TODO: get the screen resolution and make limits from that
|
||||
if (GetPosition().x < 1000 && GetPosition().y < 1000
|
||||
&& GetSize().GetWidth() < 1000
|
||||
&& GetSize().GetWidth() < 1000
|
||||
&& GetSize().GetHeight() < 1000)
|
||||
{
|
||||
file.Set("VideoWindow", "x", GetPosition().x);
|
||||
|
|
|
@ -59,15 +59,15 @@ BEGIN_EVENT_TABLE(CJitWindow, wxPanel)
|
|||
END_EVENT_TABLE()
|
||||
|
||||
CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
const wxSize& size, long style, const wxString& name)
|
||||
const wxSize& size, long style, const wxString& name)
|
||||
: wxPanel(parent, id, pos, size, style, name)
|
||||
{
|
||||
wxBoxSizer* sizerBig = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* sizerSplit = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizerSplit->Add(ppc_box = new wxTextCtrl(this, IDM_PPC_BOX, _T("(ppc)"),
|
||||
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND);
|
||||
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND);
|
||||
sizerSplit->Add(x86_box = new wxTextCtrl(this, IDM_X86_BOX, _T("(x86)"),
|
||||
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND);
|
||||
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND);
|
||||
sizerBig->Add(block_list = new JitBlockList(this, IDM_BLOCKLIST,
|
||||
wxDefaultPosition, wxSize(100, 140),
|
||||
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING),
|
||||
|
@ -107,21 +107,26 @@ void CJitWindow::Compare(u32 em_address)
|
|||
int block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(em_address);
|
||||
if (block_num < 0)
|
||||
{
|
||||
for (int i = 0; i < 500; i++) {
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(em_address - 4 * i);
|
||||
if (block_num >= 0)
|
||||
break;
|
||||
}
|
||||
if (block_num >= 0) {
|
||||
|
||||
if (block_num >= 0)
|
||||
{
|
||||
JitBlock *block = jit->GetBlockCache()->GetBlock(block_num);
|
||||
if (!(block->originalAddress <= em_address &&
|
||||
block->originalSize + block->originalAddress >= em_address))
|
||||
block->originalSize + block->originalAddress >= em_address))
|
||||
block_num = -1;
|
||||
}
|
||||
|
||||
// Do not merge this "if" with the above - block_num changes inside it.
|
||||
if (block_num < 0) {
|
||||
if (block_num < 0)
|
||||
{
|
||||
ppc_box->SetValue(StrToWxStr(StringFromFormat("(non-code address: %08x)",
|
||||
em_address)));
|
||||
em_address)));
|
||||
x86_box->SetValue(StrToWxStr(StringFromFormat("(no translation)")));
|
||||
delete[] xDis;
|
||||
return;
|
||||
|
@ -186,12 +191,14 @@ void CJitWindow::Compare(u32 em_address)
|
|||
sptr += sprintf(sptr, "%i estimated cycles\n", st.numCycles);
|
||||
|
||||
sptr += sprintf(sptr, "Num instr: PPC: %i x86: %i (blowup: %i%%)\n",
|
||||
size, num_x86_instructions, 100 * (num_x86_instructions / size - 1));
|
||||
size, num_x86_instructions, 100 * (num_x86_instructions / size - 1));
|
||||
sptr += sprintf(sptr, "Num bytes: PPC: %i x86: %i (blowup: %i%%)\n",
|
||||
size * 4, block->codeSize, 100 * (block->codeSize / (4 * size) - 1));
|
||||
size * 4, block->codeSize, 100 * (block->codeSize / (4 * size) - 1));
|
||||
|
||||
ppc_box->SetValue(StrToWxStr((char*)xDis));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ppc_box->SetValue(StrToWxStr(StringFromFormat(
|
||||
"(non-code address: %08x)", em_address)));
|
||||
x86_box->SetValue("---");
|
||||
|
@ -209,9 +216,9 @@ void CJitWindow::OnHostMessage(wxCommandEvent& event)
|
|||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_NOTIFYMAPLOADED:
|
||||
//NotifyMapLoaded();
|
||||
break;
|
||||
case IDM_NOTIFYMAPLOADED:
|
||||
//NotifyMapLoaded();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,7 +236,7 @@ enum {
|
|||
};
|
||||
|
||||
JitBlockList::JitBlockList(wxWindow* parent, const wxWindowID id,
|
||||
const wxPoint& pos, const wxSize& size, long style)
|
||||
const wxPoint& pos, const wxSize& size, long style)
|
||||
: wxListCtrl(parent, id, pos, size, style) // | wxLC_VIRTUAL)
|
||||
{
|
||||
Init();
|
||||
|
|
|
@ -90,7 +90,7 @@ void CMemoryView::OnMouseDownL(wxMouseEvent& event)
|
|||
}
|
||||
else
|
||||
{
|
||||
debugger->toggleMemCheck(YToAddress(y));
|
||||
debugger->toggleMemCheck(YToAddress(y));
|
||||
|
||||
Refresh();
|
||||
Host_UpdateBreakPointView();
|
||||
|
@ -143,17 +143,17 @@ void CMemoryView::OnPopupMenu(wxCommandEvent& event)
|
|||
switch (event.GetId())
|
||||
{
|
||||
#if wxUSE_CLIPBOARD
|
||||
case IDM_COPYADDRESS:
|
||||
case IDM_COPYADDRESS:
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format(_T("%08x"), selection)));
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_COPYHEX:
|
||||
{
|
||||
char temp[24];
|
||||
sprintf(temp, "%08x", debugger->readExtraMemory(memory, selection));
|
||||
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
|
||||
}
|
||||
break;
|
||||
case IDM_COPYHEX:
|
||||
{
|
||||
char temp[24];
|
||||
sprintf(temp, "%08x", debugger->readExtraMemory(memory, selection));
|
||||
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case IDM_TOGGLEMEMORY:
|
||||
|
@ -197,7 +197,7 @@ void CMemoryView::OnMouseDownR(wxMouseEvent& event)
|
|||
viewAsSubMenu->Append(IDM_VIEWASFP, StrToWxStr("FP value"));
|
||||
viewAsSubMenu->Append(IDM_VIEWASASCII, StrToWxStr("ASCII"));
|
||||
viewAsSubMenu->Append(IDM_VIEWASHEX, StrToWxStr("Hex"));
|
||||
menu->AppendSubMenu(viewAsSubMenu, StrToWxStr("View As:"));
|
||||
menu->AppendSubMenu(viewAsSubMenu, StrToWxStr("View As:"));
|
||||
|
||||
PopupMenu(menu);
|
||||
}
|
||||
|
@ -212,10 +212,10 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||
wxCoord w,h;
|
||||
dc.GetTextExtent(_T("0WJyq"),&w,&h,NULL,NULL,&hFont);
|
||||
if (h > rowHeight)
|
||||
rowHeight = h;
|
||||
rowHeight = h;
|
||||
dc.GetTextExtent(_T("0WJyq"),&w,&h,NULL,NULL,&DebuggerFont);
|
||||
if (h > rowHeight)
|
||||
rowHeight = h;
|
||||
rowHeight = h;
|
||||
|
||||
if (viewAsType==VIEWAS_HEX)
|
||||
dc.SetFont(hFont);
|
||||
|
@ -359,7 +359,9 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
|||
curAddress += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(dis, "INVALID VIEWAS TYPE");
|
||||
}
|
||||
|
||||
char desc[256] = "";
|
||||
if (viewAsType != VIEWAS_HEX)
|
||||
|
|
|
@ -341,13 +341,13 @@ void CMemoryWindow::onSearch(wxCommandEvent& event)
|
|||
newsize = rawData.size();
|
||||
|
||||
if (pad)
|
||||
{
|
||||
{
|
||||
tmpstr = new char[newsize + 2];
|
||||
memset(tmpstr, 0, newsize + 2);
|
||||
tmpstr[0] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
else
|
||||
{
|
||||
tmpstr = new char[newsize + 1];
|
||||
memset(tmpstr, 0, newsize + 1);
|
||||
}
|
||||
|
@ -368,7 +368,9 @@ void CMemoryWindow::onSearch(wxCommandEvent& event)
|
|||
i += 1;
|
||||
}
|
||||
delete[] tmpstr;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//Looking for an ascii string
|
||||
size = rawData.size();
|
||||
Dest.resize(size+1);
|
||||
|
|
|
@ -31,8 +31,10 @@ static const char *special_reg_names[] = {
|
|||
"PC", "LR", "CTR", "CR", "FPSCR", "MSR", "SRR0", "SRR1", "Exceptions", "Int Mask", "Int Cause",
|
||||
};
|
||||
|
||||
static u32 GetSpecialRegValue(int reg) {
|
||||
switch (reg) {
|
||||
static u32 GetSpecialRegValue(int reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 0: return PowerPC::ppcState.pc;
|
||||
case 1: return PowerPC::ppcState.spr[SPR_LR];
|
||||
case 2: return PowerPC::ppcState.spr[SPR_CTR];
|
||||
|
@ -50,8 +52,10 @@ static u32 GetSpecialRegValue(int reg) {
|
|||
|
||||
wxString CRegTable::GetValue(int row, int col)
|
||||
{
|
||||
if (row < 32) {
|
||||
switch (col) {
|
||||
if (row < 32)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0: return StrToWxStr(GetGPRName(row));
|
||||
case 1: return wxString::Format(wxT("%08x"), GPR(row));
|
||||
case 2: return StrToWxStr(GetFPRName(row));
|
||||
|
@ -59,20 +63,26 @@ wxString CRegTable::GetValue(int row, int col)
|
|||
case 4: return wxString::Format(wxT("%016llx"), riPS1(row));
|
||||
default: return wxEmptyString;
|
||||
}
|
||||
} else {
|
||||
if (row - 32 < NUM_SPECIALS) {
|
||||
switch (col) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (row - 32 < NUM_SPECIALS)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0: return StrToWxStr(special_reg_names[row - 32]);
|
||||
case 1: return wxString::Format(wxT("%08x"), GetSpecialRegValue(row - 32));
|
||||
default: return wxEmptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxEmptyString;
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
static void SetSpecialRegValue(int reg, u32 value) {
|
||||
switch (reg) {
|
||||
static void SetSpecialRegValue(int reg, u32 value)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 0: PowerPC::ppcState.pc = value; break;
|
||||
case 1: PowerPC::ppcState.spr[SPR_LR] = value; break;
|
||||
case 2: PowerPC::ppcState.spr[SPR_CTR] = value; break;
|
||||
|
@ -94,15 +104,19 @@ void CRegTable::SetValue(int row, int col, const wxString& strNewVal)
|
|||
u32 newVal = 0;
|
||||
if (TryParse(WxStrToStr(strNewVal), &newVal))
|
||||
{
|
||||
if (row < 32) {
|
||||
if (row < 32)
|
||||
{
|
||||
if (col == 1)
|
||||
GPR(row) = newVal;
|
||||
else if (col == 3)
|
||||
riPS0(row) = newVal;
|
||||
else if (col == 4)
|
||||
riPS1(row) = newVal;
|
||||
} else {
|
||||
if ((row - 32 < NUM_SPECIALS) && (col == 1)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((row - 32 < NUM_SPECIALS) && (col == 1))
|
||||
{
|
||||
SetSpecialRegValue(row - 32, newVal);
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +149,8 @@ wxGridCellAttr *CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
|
|||
attr->SetBackgroundColour(wxColour(wxT("#FFFFFF"))); //wxWHITE
|
||||
attr->SetFont(DebuggerFont);
|
||||
|
||||
switch (col) {
|
||||
switch (col)
|
||||
{
|
||||
case 1:
|
||||
attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
|
||||
break;
|
||||
|
@ -149,11 +164,13 @@ wxGridCellAttr *CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
|
|||
}
|
||||
|
||||
bool red = false;
|
||||
switch (col) {
|
||||
switch (col)
|
||||
{
|
||||
case 1: red = row < 32 ? m_CachedRegHasChanged[row] : m_CachedSpecialRegHasChanged[row-32]; break;
|
||||
case 3:
|
||||
case 4: red = row < 32 ? m_CachedFRegHasChanged[row][col-3] : false; break;
|
||||
}
|
||||
|
||||
attr->SetTextColour(red ? wxColor(wxT("#FF0000")) : wxColor(wxT("#000000")));
|
||||
attr->IncRef();
|
||||
return attr;
|
||||
|
|
|
@ -28,8 +28,8 @@ END_EVENT_TABLE()
|
|||
|
||||
|
||||
CRegisterWindow::CRegisterWindow(wxWindow* parent, wxWindowID id,
|
||||
const wxPoint& position, const wxSize& size,
|
||||
long style, const wxString& name)
|
||||
const wxPoint& position, const wxSize& size,
|
||||
long style, const wxString& name)
|
||||
: wxPanel(parent, id, position, size, style, name)
|
||||
, m_GPRGridView(NULL)
|
||||
{
|
||||
|
|
|
@ -387,18 +387,23 @@ void FifoPlayerDlg::OnCheckEarlyMemoryUpdates(wxCommandEvent& event)
|
|||
|
||||
void FifoPlayerDlg::OnSaveFile(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
// Pointer to the file data that was created as a result of recording.
|
||||
FifoDataFile *file = FifoRecorder::GetInstance().GetRecordedFile();
|
||||
|
||||
if (file)
|
||||
{
|
||||
{
|
||||
// Bring up a save file dialog. The location the user chooses will be assigned to this variable.
|
||||
wxString path = wxSaveFileSelector(_("Dolphin FIFO"), wxT("dff"), wxEmptyString, this);
|
||||
|
||||
// Has a valid file path
|
||||
if (!path.empty())
|
||||
{
|
||||
// Attempt to save the file to the path the user chose
|
||||
wxBeginBusyCursor();
|
||||
bool result = file->Save(WxStrToStr(path).c_str());
|
||||
wxEndBusyCursor();
|
||||
|
||||
// Wasn't able to save the file, shit's whack, yo.
|
||||
if (!result)
|
||||
PanicAlert("Error saving file");
|
||||
}
|
||||
|
@ -409,14 +414,21 @@ void FifoPlayerDlg::OnRecordStop(wxCommandEvent& WXUNUSED(event))
|
|||
{
|
||||
FifoRecorder& recorder = FifoRecorder::GetInstance();
|
||||
|
||||
// Recorder is still recording
|
||||
if (recorder.IsRecording())
|
||||
{
|
||||
// Then stop recording
|
||||
recorder.StopRecording();
|
||||
|
||||
// and disable the button to stop recording
|
||||
m_RecordStop->Disable();
|
||||
}
|
||||
else
|
||||
else // Recorder is actually about to start recording
|
||||
{
|
||||
// So start recording
|
||||
recorder.StartRecording(m_FramesToRecord, RecordingFinished);
|
||||
|
||||
// and change the button label accordingly.
|
||||
m_RecordStop->SetLabel(_("Stop"));
|
||||
}
|
||||
}
|
||||
|
@ -839,10 +851,12 @@ void FifoPlayerDlg::UpdateAnalyzerGui()
|
|||
if ((int)m_framesList->GetCount() != num_frames)
|
||||
{
|
||||
m_framesList->Clear();
|
||||
|
||||
for (int i = 0; i < num_frames; ++i)
|
||||
{
|
||||
m_framesList->Append(wxString::Format(wxT("Frame %i"), i));
|
||||
}
|
||||
|
||||
wxCommandEvent ev = wxCommandEvent(wxEVT_COMMAND_LISTBOX_SELECTED);
|
||||
ev.SetInt(-1);
|
||||
OnFrameListSelectionChanged(ev);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue