Merge branch 'master' into wii-network

Conflicts:
	Source/Core/Core/CMakeLists.txt
This commit is contained in:
Matthew Parlane
2013-04-11 19:55:36 +12:00
369 changed files with 21804 additions and 18869 deletions
+2 -2
View File
@@ -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");
}
}
+1 -1
View File
@@ -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;
}
+9 -2
View File
@@ -32,6 +32,7 @@
#include <list>
#include <deque>
#include <string>
#include <type_traits>
#include "Common.h"
#include "FileUtil.h"
@@ -139,11 +140,17 @@ public:
template <typename T>
void Do(T& x)
{
// TODO: Bad, Do(some_non_POD) will compile and fail at runtime
// type_traits are not fully supported everywhere yet
// Ideally this would be std::is_trivially_copyable, but not enough support yet
static_assert(std::is_pod<T>::value, "Only sane for POD types");
DoVoid((void*)&x, sizeof(x));
}
template <typename T>
void DoPOD(T& x)
{
DoVoid((void*)&x, sizeof(x));
}
template <typename T>
void DoPointer(T*& x, T* const base)
+9 -6
View File
@@ -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;
+5 -4
View File
@@ -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;
+19 -6
View File
@@ -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];
@@ -724,11 +724,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
@@ -744,6 +744,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());
+4 -1
View File
@@ -133,7 +133,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();
+1
View File
@@ -120,6 +120,7 @@ LogManager::~LogManager()
delete m_fileLog;
delete m_consoleLog;
delete m_debuggerLog;
}
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
+1 -1
View File
@@ -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
+7
View File
@@ -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
+7
View File
@@ -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
+2 -2
View File
@@ -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"
-1
View File
@@ -71,7 +71,6 @@ set(SRCS Src/ActionReplay.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_CARD.cpp
Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
+1 -5
View File
@@ -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" />
@@ -469,11 +468,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" />
+1 -13
View File
@@ -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>
@@ -749,21 +746,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>
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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"
+2 -2
View File
@@ -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")
{
+3 -2
View File
@@ -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),
@@ -84,6 +84,7 @@ void SCoreStartupParameter::LoadDefaults()
bSyncGPU = false;
bFastDiscSpeed = false;
bMergeBlocks = false;
bEnableMemcardSaving = true;
SelectedLanguage = 0;
bWii = false;
bDPL2Decoder = false;
@@ -329,7 +330,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;
}
}
+1
View File
@@ -108,6 +108,7 @@ struct SCoreStartupParameter
bool bHLE_BS2;
bool bEnableCheats;
bool bMergeBlocks;
bool bEnableMemcardSaving;
bool bDPL2Decoder;
int iLatency;
+3 -6
View File
@@ -165,14 +165,11 @@ u16 dsp_read_accelerator()
// Somehow, YN1 and YN2 must be initialized with their "loop" values,
// so yeah, it seems likely that we should raise an exception to let
// the DSP program do that, at least if DSP_FORMAT == 0x0A.
if (Address >= EndAddress)
if ((Address & ~1) == (EndAddress & ~1))
{
// Set address back to start address.
if (DSPHost_Wii() || (Address == EndAddress))
{
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
DSPCore_SetException(EXP_ACCOV);
}
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
DSPCore_SetException(EXP_ACCOV);
}
g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16;
+2 -2
View File
@@ -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)
{
+1 -1
View File
@@ -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
+10 -10
View File
@@ -131,8 +131,8 @@ static unsigned int g_AIDSampleRate = 32000;
void DoState(PointerWrap &p)
{
p.Do(m_Control);
p.Do(m_Volume);
p.DoPOD(m_Control);
p.DoPOD(m_Volume);
p.Do(m_SampleCounter);
p.Do(m_InterruptTiming);
p.Do(g_LastCPUTime);
@@ -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);
+7 -6
View File
@@ -223,9 +223,9 @@ void DoState(PointerWrap &p)
{
if (!g_ARAM.wii_mode)
p.DoArray(g_ARAM.ptr, g_ARAM.size);
p.Do(g_dspState);
p.Do(g_audioDMA);
p.Do(g_arDMA);
p.DoPOD(g_dspState);
p.DoPOD(g_audioDMA);
p.DoPOD(g_arDMA);
p.Do(g_ARAM_Info);
p.Do(g_AR_MODE);
p.Do(g_AR_REFRESH);
@@ -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
+3 -3
View File
@@ -157,8 +157,8 @@ void DSPHLE::DoState(PointerWrap &p)
}
}
p.Do(m_DSPControl);
p.Do(m_dspState);
p.DoPOD(m_DSPControl);
p.DoPOD(m_dspState);
int ucode_crc = IUCode::GetCRC(m_pUCode);
int ucode_crc_beforeLoad = ucode_crc;
@@ -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,15 +27,17 @@
#endif
#include "Common.h"
#include "UCode_AX_Structs.h"
#include "UCode_AXStructs.h"
#include "../../DSP.h"
#include "CoreTiming.h"
#include "Core.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
@@ -67,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
};
@@ -129,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)
@@ -137,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
@@ -146,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
@@ -201,105 +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 >= acc_end_addr)
{
// loop back to loop_addr.
if (Core::g_CoreStartupParameter.bWii || *acc_cur_addr == acc_end_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);
@@ -307,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];
@@ -318,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;
@@ -331,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.
@@ -394,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
{
+2 -2
View File
@@ -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++;
}
+6 -6
View File
@@ -229,14 +229,14 @@ void ExecuteCommand(UDICR& _DICR);
void DoState(PointerWrap &p)
{
p.Do(m_DISR);
p.Do(m_DICVR);
p.DoPOD(m_DISR);
p.DoPOD(m_DICVR);
p.DoArray(m_DICMDBUF, 3);
p.Do(m_DIMAR);
p.Do(m_DILENGTH);
p.Do(m_DICR);
p.Do(m_DIIMMBUF);
p.Do(m_DICFG);
p.DoPOD(m_DICFG);
p.Do(LoopStart);
p.Do(AudioPos);
@@ -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)
+7 -7
View File
@@ -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;
}
@@ -282,7 +282,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
void CEXIChannel::DoState(PointerWrap &p)
{
p.Do(m_Status);
p.DoPOD(m_Status);
p.Do(m_DMAMemoryAddress);
p.Do(m_DMALength);
p.Do(m_Control);
@@ -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;
}
}
+13 -13
View File
@@ -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;
+1 -1
View File
@@ -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
+7 -4
View File
@@ -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)
+14
View File
@@ -96,6 +96,20 @@ void STACKALIGN CheckGatherPipe()
// move back the spill bytes
memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount);
// Profile where the FIFO writes are occurring.
if (jit && PC != 0 && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end()))
{
// Log only stores, fp stores and ps stores, filtering out other instructions arrived via optimizeGatherPipe
int type = GetOpInfo(Memory::ReadUnchecked_U32(PC))->type;
if (type == OPTYPE_STORE || type == OPTYPE_STOREFP || (type == OPTYPE_PS && !strcmp(GetOpInfo(Memory::ReadUnchecked_U32(PC))->opname, "psq_st")))
{
jit->js.fifoWriteAddresses.insert(PC);
// Invalidate the JIT block so that it gets recompiled with the external exception check included.
jit->GetBlockCache()->InvalidateICache(PC, 4);
}
}
}
}
@@ -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:
+2 -2
View File
@@ -257,8 +257,8 @@ void DoState(PointerWrap &p)
}
}
p.Do(g_Poll);
p.Do(g_ComCSR);
p.Do(g_StatusReg);
p.DoPOD(g_ComCSR);
p.DoPOD(g_StatusReg);
p.Do(g_EXIClockCount);
p.Do(g_SIBuffer);
}
@@ -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");
}
+1 -1
View File
@@ -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;
}
+11 -11
View File
@@ -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);
+10 -10
View File
@@ -72,8 +72,8 @@ static int fields = 2;
void DoState(PointerWrap &p)
{
p.Do(m_VerticalTimingRegister);
p.Do(m_DisplayControlRegister);
p.DoPOD(m_VerticalTimingRegister);
p.DoPOD(m_DisplayControlRegister);
p.Do(m_HTiming0);
p.Do(m_HTiming1);
p.Do(m_VBlankTimingOdd);
@@ -89,7 +89,7 @@ void DoState(PointerWrap &p)
p.DoArray(m_InterruptRegister, 4);
p.DoArray(m_LatchRegister, 2);
p.Do(m_HorizontalStepping);
p.Do(m_HorizontalScaling);
p.DoPOD(m_HorizontalScaling);
p.Do(m_FilterCoefTables);
p.Do(m_UnkAARegister);
p.Do(m_Clock);
@@ -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]
);
+2 -2
View File
@@ -111,7 +111,7 @@ void DoState(PointerWrap &p)
{
p.Do(ppc_msg);
p.Do(arm_msg);
p.Do(ctrl);
p.DoPOD(ctrl);
p.Do(ppc_irq_flags);
p.Do(ppc_irq_masks);
p.Do(arm_irq_flags);
@@ -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);
}
+25 -15
View File
@@ -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;
}
}
}
+40 -58
View File
@@ -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,8 +57,10 @@ Wiimote::Wiimote()
#elif defined(_WIN32)
, dev_handle(0), stack(MSBT_STACK_UNKNOWN)
#endif
, m_last_data_report(Report((u8 *)NULL, 0))
, m_channel(0), m_run_thread(false)
, m_last_input_report()
, m_channel(0)
, m_rumble_state()
, m_run_thread(false)
{
#if defined(__linux__) && HAVE_BLUEZ
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
@@ -73,11 +75,27 @@ Wiimote::~Wiimote()
Disconnect();
ClearReadQueue();
m_write_reports.Clear();
}
// clear write queue
Report rpt;
while (m_write_reports.Pop(rpt))
delete[] rpt.first;
// to be called from CPU thread
void Wiimote::WriteReport(Report rpt)
{
if (rpt.size() >= 3)
{
bool const new_rumble_state = (rpt[2] & 0x1) != 0;
if (WM_RUMBLE == rpt[1] && new_rumble_state == m_rumble_state)
{
// If this is a rumble report and the rumble state didn't change, ignore
//ERROR_LOG(WIIMOTE, "Ignoring rumble report.");
return;
}
m_rumble_state = new_rumble_state;
}
m_write_reports.Push(std::move(rpt));
}
// to be called from CPU thread
@@ -85,17 +103,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);
WriteReport(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 +126,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 +162,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);
WriteReport(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 +223,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 +240,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 +280,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 +293,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 +322,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 +343,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 +372,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 +388,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 +399,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 +499,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 +516,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 +542,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 +560,7 @@ void DoneWithWiimote(int index)
}
}
// else, just disconnect the wiimote
// else, just disconnect the Wiimote
HandleWiimoteDisconnect(index);
}
@@ -563,7 +577,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 +597,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 +605,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 +647,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,17 +98,20 @@ public:
#endif
protected:
Report m_last_data_report;
Report m_last_input_report;
u16 m_channel;
private:
void ClearReadQueue();
void WriteReport(Report rpt);
int IORead(u8* buf);
int IOWrite(u8 const* buf, int len);
void ThreadFunc();
bool m_rumble_state;
bool m_run_thread;
std::thread m_wiimote_thread;
@@ -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
+1 -1
View File
@@ -544,7 +544,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;
@@ -198,7 +198,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
{
@@ -237,7 +237,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
{
@@ -136,7 +136,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;
}
@@ -323,7 +323,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;
@@ -374,7 +374,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;
@@ -584,7 +584,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())
{
@@ -691,7 +691,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)
{
@@ -786,14 +786,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
{
@@ -844,8 +844,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;
@@ -992,7 +992,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
{
@@ -109,8 +109,8 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
p.Do(m_ControllerBD);
p.Do(m_CtrlSetup);
p.Do(m_ACLSetup);
p.Do(m_HCIEndpoint);
p.Do(m_ACLEndpoint);
p.DoPOD(m_HCIEndpoint);
p.DoPOD(m_ACLEndpoint);
p.Do(m_last_ticks);
p.DoArray(m_PacketCount,4);
p.Do(m_ScanEnable);
@@ -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;
}
@@ -51,6 +51,12 @@ struct SQueuedEvent
}
};
// Hacks for ChunkFile to accept SQueuedEvent as POD
namespace std
{
template <>
struct is_pod<SQueuedEvent> : std::true_type {};
}
// Important to remember that this class is for /dev/usb/oh1/57e/305 ONLY
// /dev/usb/oh1 -> internal usb bus
@@ -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);
}
+10
View File
@@ -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)
{
+1
View File
@@ -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);
+2 -2
View File
@@ -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();
@@ -320,7 +320,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);
}
}
+25 -1
View File
@@ -611,6 +611,30 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
js.firstFPInstructionFound = true;
}
// Add an external exception check if the instruction writes to the FIFO.
if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end())
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT));
FixupBranch clearInt = J_CC(CC_NZ, true);
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
FixupBranch noExtException = J_CC(CC_Z, true);
TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
FixupBranch noExtIntEnable = J_CC(CC_Z, true);
TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH));
FixupBranch noCPInt = J_CC(CC_Z, true);
MOV(32, M(&PC), Imm32(ops[i].address));
WriteExternalExceptionExit();
SetJumpTarget(noCPInt);
SetJumpTarget(noExtIntEnable);
SetJumpTarget(noExtException);
SetJumpTarget(clearInt);
}
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
{
gpr.Flush(FLUSH_ALL);
@@ -655,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)
{
+1 -1
View File
@@ -1269,7 +1269,7 @@ static const unsigned alwaysUsedList[] = {
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck,
DSIExceptionCheck, ISIException, BreakPointCheck,
DSIExceptionCheck, ISIException, ExtExceptionCheck, BreakPointCheck,
Int3, Tramp, Nop
};
static const unsigned extra8RegList[] = {
+4 -1
View File
@@ -168,7 +168,7 @@ enum Opcode {
// used for exception checking, at least until someone
// has a better idea of integrating it
FPExceptionCheck, DSIExceptionCheck,
ISIException, BreakPointCheck,
ISIException, ExtExceptionCheck, BreakPointCheck,
// "Opcode" representing a register too far away to
// reference directly; this is a size optimization
Tramp,
@@ -411,6 +411,9 @@ public:
InstLoc EmitISIException(InstLoc dest) {
return EmitUOp(ISIException, dest);
}
InstLoc EmitExtExceptionCheck(InstLoc pc) {
return EmitUOp(ExtExceptionCheck, pc);
}
InstLoc EmitBreakPointCheck(InstLoc pc) {
return EmitUOp(BreakPointCheck, pc);
}
@@ -762,6 +762,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
case FPExceptionCheck:
case DSIExceptionCheck:
case ISIException:
case ExtExceptionCheck:
case BreakPointCheck:
case Int3:
case Tramp:
@@ -1940,6 +1941,27 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Jit->WriteExceptionExit();
break;
}
case ExtExceptionCheck: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT));
FixupBranch clearInt = Jit->J_CC(CC_NZ);
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
FixupBranch noExtException = Jit->J_CC(CC_Z);
Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
FixupBranch noExtIntEnable = Jit->J_CC(CC_Z);
Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH));
FixupBranch noCPInt = Jit->J_CC(CC_Z);
Jit->MOV(32, M(&PC), Imm32(InstLoc));
Jit->WriteExceptionExit();
Jit->SetJumpTarget(noCPInt);
Jit->SetJumpTarget(noExtIntEnable);
Jit->SetJumpTarget(noExtException);
Jit->SetJumpTarget(clearInt);
break;
}
case BreakPointCheck: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
@@ -679,6 +679,11 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address));
}
if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end())
{
ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address));
}
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
{
ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address));
@@ -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;
@@ -74,6 +74,8 @@ protected:
u8* rewriteStart;
JitBlock *curBlock;
std::set<u32> fifoWriteAddresses;
};
public:
@@ -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");
+2 -2
View File
@@ -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));
+1 -1
View File
@@ -80,7 +80,7 @@ void DoState(PointerWrap &p)
// rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer();
// *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :)
p.Do(ppcState);
p.DoPOD(ppcState);
// SystemTimers::DecrementerSet();
// SystemTimers::TimeBaseSet();
+2 -2
View File
@@ -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];
+3
View File
@@ -65,6 +65,9 @@ public:
virtual ECountry GetCountry() const = 0;
virtual u64 GetSize() const = 0;
// Size on disc (compressed size)
virtual u64 GetRawSize() const = 0;
};
// Generic Switch function for all volumes
@@ -240,6 +240,10 @@ u64 CVolumeDirectory::GetSize() const
return 0;
}
u64 CVolumeDirectory::GetRawSize() const
{
return GetSize();
}
std::string CVolumeDirectory::ExtractDirectoryName(const std::string& _rDirectory)
{
+1
View File
@@ -60,6 +60,7 @@ public:
ECountry GetCountry() const;
u64 GetSize() const;
u64 GetRawSize() const;
void BuildFST();
+8
View File
@@ -138,6 +138,14 @@ u64 CVolumeGC::GetSize() const
return 0;
}
u64 CVolumeGC::GetRawSize() const
{
if (m_pReader)
return m_pReader->GetRawSize();
else
return 0;
}
bool CVolumeGC::IsDiscTwo() const
{
bool discTwo;

Some files were not shown because too many files have changed in this diff Show More