mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-08-26 12:50:44 -05:00
Merge branch 'master' into wii-network
Conflicts: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp Source/VSProps/Dolphin.Win32.props Source/VSProps/Dolphin.x64.props
This commit is contained in:
@@ -210,7 +210,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
<None Include="Src\SConscript" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.vcxproj">
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Src\SConscript" />
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- python -*-
|
||||
|
||||
Import('env')
|
||||
import sys
|
||||
|
||||
files = [
|
||||
'Src/AudioCommon.cpp',
|
||||
'Src/AudioCommonConfig.cpp',
|
||||
'Src/Mixer.cpp',
|
||||
'Src/NullSoundStream.cpp',
|
||||
'Src/WaveFile.cpp',
|
||||
]
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
files += ['Src/CoreAudioSoundStream.cpp']
|
||||
elif sys.platform == 'win32':
|
||||
files += ['Src/DSoundStream.cpp']
|
||||
files += ['Src/XAudio2Stream.cpp']
|
||||
else:
|
||||
if env['HAVE_ALSA']:
|
||||
files += ['Src/AlsaSoundStream.cpp']
|
||||
if env['HAVE_AO']:
|
||||
files += ['Src/AOSoundStream.cpp']
|
||||
if env['HAVE_OPENAL']:
|
||||
files += ['Src/OpenALStream.cpp', 'Src/aldlist.cpp']
|
||||
if env['HAVE_PULSEAUDIO']:
|
||||
files += ['Src/PulseAudioStream.cpp']
|
||||
|
||||
env['LIBS'] += env.StaticLibrary('audiocommon', files)
|
||||
@@ -31,7 +31,6 @@ void AudioCommonConfig::Load()
|
||||
IniFile file;
|
||||
file.Load(File::GetUserPath(F_DSPCONFIG_IDX));
|
||||
|
||||
file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true);
|
||||
file.Get("Config", "EnableJIT", &m_EnableJIT, true);
|
||||
file.Get("Config", "DumpAudio", &m_DumpAudio, false);
|
||||
#if defined __linux__ && HAVE_ALSA
|
||||
@@ -53,7 +52,6 @@ void AudioCommonConfig::SaveSettings()
|
||||
IniFile file;
|
||||
file.Load(File::GetUserPath(F_DSPCONFIG_IDX));
|
||||
|
||||
file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic);
|
||||
file.Set("Config", "EnableJIT", m_EnableJIT);
|
||||
file.Set("Config", "DumpAudio", m_DumpAudio);
|
||||
file.Set("Config", "Backend", sBackend);
|
||||
@@ -67,7 +65,6 @@ void AudioCommonConfig::SaveSettings()
|
||||
void AudioCommonConfig::Update() {
|
||||
if (soundStream) {
|
||||
soundStream->GetMixer()->SetThrottle(SConfig::GetInstance().m_Framelimit == 2);
|
||||
soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic);
|
||||
soundStream->SetVolume(m_Volume);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
struct AudioCommonConfig
|
||||
{
|
||||
bool m_EnableDTKMusic;
|
||||
bool m_EnableJIT;
|
||||
bool m_DumpAudio;
|
||||
int m_Volume;
|
||||
|
||||
@@ -136,8 +136,7 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||
if (m_AIplaying) {
|
||||
Premix(samples, numLeft);
|
||||
|
||||
if (m_EnableDTKMusic)
|
||||
AudioInterface::Callback_GetStreaming(samples, numLeft, m_sampleRate);
|
||||
AudioInterface::Callback_GetStreaming(samples, numLeft, m_sampleRate);
|
||||
|
||||
g_wave_writer.AddStereoSamples(samples, numLeft);
|
||||
}
|
||||
@@ -147,11 +146,8 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||
Premix(samples, numSamples);
|
||||
|
||||
// Add the DTK Music
|
||||
if (m_EnableDTKMusic)
|
||||
{
|
||||
// Re-sampling is done inside
|
||||
AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate);
|
||||
}
|
||||
// Re-sampling is done inside
|
||||
AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ public:
|
||||
unsigned int GetSampleRate() {return m_sampleRate;}
|
||||
|
||||
void SetThrottle(bool use) { m_throttle = use;}
|
||||
void SetDTKMusic(bool use) { m_EnableDTKMusic = use;}
|
||||
|
||||
// TODO: do we need this
|
||||
bool IsHLEReady() { return m_HLEready;}
|
||||
@@ -103,7 +102,6 @@ protected:
|
||||
bool m_HLEready;
|
||||
bool m_logAudio;
|
||||
|
||||
bool m_EnableDTKMusic;
|
||||
bool m_throttle;
|
||||
|
||||
short m_buffer[MAX_SAMPLES * 2];
|
||||
|
||||
@@ -108,27 +108,21 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile />
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile />
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile />
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
@@ -137,9 +131,7 @@
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile />
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
@@ -148,9 +140,7 @@
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile />
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
@@ -159,9 +149,7 @@
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile />
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
@@ -270,7 +258,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
<None Include="Src\SConscript" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -126,7 +126,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
<None Include="Src\SConscript" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Crypto">
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# -*- python -*-
|
||||
|
||||
Import('env')
|
||||
import os
|
||||
import sys
|
||||
|
||||
out_contents =\
|
||||
'#define SCM_REV_STR "' + env['gitrev'] + '"\n' +\
|
||||
'#define SCM_DESC_STR "' + env['gitdesc'] + '"\n' +\
|
||||
'#define SCM_BRANCH_STR "' + env['gitbranch'] + '"\n' +\
|
||||
'#define SCM_IS_MASTER ' + ('1' if env['gitbranch'] == 'master' else '0') + '\n\n'
|
||||
|
||||
Execute(Delete('Src/scmrev.h'))
|
||||
outfile = open('Src/scmrev.h', 'w')
|
||||
outfile.write(out_contents)
|
||||
outfile.close()
|
||||
|
||||
files = [
|
||||
'Src/ABI.cpp',
|
||||
'Src/BreakPoints.cpp',
|
||||
'Src/CDUtils.cpp',
|
||||
'Src/CPUDetect.cpp',
|
||||
'Src/ColorUtil.cpp',
|
||||
'Src/ConsoleListener.cpp',
|
||||
'Src/Crypto/aes_cbc.cpp',
|
||||
'Src/Crypto/aes_core.cpp',
|
||||
'Src/Crypto/bn.cpp',
|
||||
'Src/Crypto/ec.cpp',
|
||||
'Src/Crypto/md5.cpp',
|
||||
'Src/Crypto/sha1.cpp',
|
||||
'Src/FileSearch.cpp',
|
||||
'Src/FileUtil.cpp',
|
||||
'Src/Hash.cpp',
|
||||
'Src/IniFile.cpp',
|
||||
'Src/LogManager.cpp',
|
||||
'Src/MathUtil.cpp',
|
||||
'Src/MemArena.cpp',
|
||||
'Src/MemoryUtil.cpp',
|
||||
'Src/Misc.cpp',
|
||||
'Src/MsgHandler.cpp',
|
||||
'Src/NandPaths.cpp',
|
||||
'Src/SDCardUtil.cpp',
|
||||
'Src/StringUtil.cpp',
|
||||
'Src/SymbolDB.cpp',
|
||||
'Src/SysConf.cpp',
|
||||
'Src/Thread.cpp',
|
||||
'Src/Thunk.cpp',
|
||||
'Src/Timer.cpp',
|
||||
'Src/Version.cpp',
|
||||
'Src/VideoBackendBase.cpp',
|
||||
'Src/x64Analyzer.cpp',
|
||||
'Src/x64Emitter.cpp',
|
||||
]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
files += ['Src/ExtendedTrace.cpp']
|
||||
files += ['Src/stdafx.cpp']
|
||||
|
||||
env['CPPPATH'] += ['Src']
|
||||
env['LIBS'] += env.StaticLibrary('common', files)
|
||||
@@ -7,13 +7,11 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="make_scmrev.h.js">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">cscript /nologo /E:JScript "make_scmrev.h.js"</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Updating scmrev.h</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dummy</Outputs>
|
||||
</CustomBuild>
|
||||
<None Include="make_scmrev.h.js">
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="force_rebuild.h" />
|
||||
<ClInclude Include="Src\scmrev.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
@@ -37,25 +35,9 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
<Command>cscript /nologo /E:JScript "make_scmrev.h.js"</Command>
|
||||
</PreBuildEvent>
|
||||
<CustomBuild>
|
||||
<Outputs>
|
||||
</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Common.h"
|
||||
#include "DebugInterface.h"
|
||||
#include "BreakPoints.h"
|
||||
#include "../../Core/Src/PowerPC/JitCommon/JitBase.h"
|
||||
#include <sstream>
|
||||
|
||||
bool BreakPoints::IsAddressBreakPoint(u32 _iAddress)
|
||||
@@ -70,7 +71,11 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps)
|
||||
void BreakPoints::Add(const TBreakPoint& bp)
|
||||
{
|
||||
if (!IsAddressBreakPoint(bp.iAddress))
|
||||
{
|
||||
m_BreakPoints.push_back(bp);
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Add(u32 em_address, bool temp)
|
||||
@@ -83,21 +88,35 @@ void BreakPoints::Add(u32 em_address, bool temp)
|
||||
pt.iAddress = em_address;
|
||||
|
||||
m_BreakPoints.push_back(pt);
|
||||
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(em_address, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Remove(u32 _iAddress)
|
||||
void BreakPoints::Remove(u32 em_address)
|
||||
{
|
||||
for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
|
||||
{
|
||||
if (i->iAddress == _iAddress)
|
||||
if (i->iAddress == em_address)
|
||||
{
|
||||
m_BreakPoints.erase(i);
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(em_address, 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Clear()
|
||||
{
|
||||
for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
|
||||
{
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(i->iAddress, 4);
|
||||
m_BreakPoints.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
MemChecks::TMemChecksStr MemChecks::GetStrings() const
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
|
||||
// Remove Breakpoint
|
||||
void Remove(u32 _iAddress);
|
||||
void Clear() { m_BreakPoints.clear(); };
|
||||
void Clear();
|
||||
|
||||
void DeleteByAddress(u32 _Address);
|
||||
|
||||
|
||||
@@ -103,8 +103,6 @@ private:
|
||||
//CrtDebugBreak breakAt(614);
|
||||
#endif // end DEBUG/FAST
|
||||
|
||||
#elif defined HAVE_CONFIG_H
|
||||
#include "config.h" // SCons autoconfiguration defines
|
||||
#endif
|
||||
|
||||
// Windows compatibility
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifdef _WIN32
|
||||
#define SLEEP(x) Sleep(x)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define SLEEP(x) usleep(x*1000)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -121,6 +121,8 @@
|
||||
#define GC_MEMCARDA "MemoryCardA"
|
||||
#define GC_MEMCARDB "MemoryCardB"
|
||||
|
||||
#define WII_STATE "state.dat"
|
||||
|
||||
#define WII_SETTING "setting.txt"
|
||||
|
||||
#define GECKO_CODE_HANDLER "codehandler.bin"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
// Increment this every time you change shader generation code.
|
||||
enum
|
||||
{
|
||||
LINEAR_DISKCACHE_VER = 6972
|
||||
LINEAR_DISKCACHE_VER = 6975
|
||||
};
|
||||
|
||||
// On disk format:
|
||||
|
||||
@@ -161,6 +161,7 @@ void LoadDefaultSSEState();
|
||||
float MathFloatVectorSum(const std::vector<float>&);
|
||||
|
||||
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define ROUND_DOWN(x, a) ((x) & ~((a) - 1))
|
||||
|
||||
|
||||
// Tiny matrix/vector library.
|
||||
|
||||
@@ -1,207 +1,207 @@
|
||||
// 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 "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
#include <unistd.h>
|
||||
#define PAGE_MASK (getpagesize() - 1)
|
||||
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
|
||||
#endif
|
||||
|
||||
// This is purposely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
|
||||
void* AllocateExecutableMemory(size_t size, bool low)
|
||||
{
|
||||
// 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 "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
#include <unistd.h>
|
||||
#define PAGE_MASK (getpagesize() - 1)
|
||||
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
|
||||
#endif
|
||||
|
||||
// This is purposely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
|
||||
void* AllocateExecutableMemory(size_t size, bool low)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
static char *map_hint = 0;
|
||||
#if defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
// This OS has no flag to enforce allocation below the 4 GB boundary,
|
||||
// but if we hint that we want a low address it is very likely we will
|
||||
// get one.
|
||||
// An older version of this code used MAP_FIXED, but that has the side
|
||||
// effect of discarding already mapped pages that happen to be in the
|
||||
// requested virtual memory range (such as the emulated RAM, sometimes).
|
||||
if (low && (!map_hint))
|
||||
map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
|
||||
#endif
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANON | MAP_PRIVATE
|
||||
#if defined(__x86_64__) && defined(MAP_32BIT)
|
||||
| (low ? MAP_32BIT : 0)
|
||||
#endif
|
||||
, -1, 0);
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
// printf("Mapped executable memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (ptr == MAP_FAILED)
|
||||
{
|
||||
ptr = NULL;
|
||||
#else
|
||||
if (ptr == NULL)
|
||||
{
|
||||
#endif
|
||||
PanicAlert("Failed to allocate executable memory");
|
||||
}
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
else
|
||||
{
|
||||
if (low)
|
||||
{
|
||||
map_hint += size;
|
||||
map_hint = (char*)round_page(map_hint); /* round up to the next page */
|
||||
// printf("Next map will (hopefully) be at %p\n", map_hint);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64)
|
||||
if ((u64)ptr >= 0x80000000 && low == true)
|
||||
PanicAlert("Executable memory ended up above 2GB!");
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateMemoryPages(size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
void* ptr = mmap(0, size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
if (ptr == NULL)
|
||||
PanicAlert("Failed to allocate raw memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = _aligned_malloc(size,alignment);
|
||||
#else
|
||||
void* ptr = NULL;
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
;
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
if (ptr == NULL)
|
||||
PanicAlert("Failed to allocate aligned memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* ptr, size_t size)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
||||
ptr = NULL; // Is this our responsibility?
|
||||
|
||||
#else
|
||||
munmap(ptr, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void FreeAlignedMemory(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
_aligned_free(ptr);
|
||||
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
||||
PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
|
||||
PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string MemUsage()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "psapi")
|
||||
DWORD processID = GetCurrentProcessId();
|
||||
HANDLE hProcess;
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
std::string Ret;
|
||||
|
||||
// Print information about the memory usage of the process.
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
|
||||
if (NULL == hProcess) return "MemUsage Error";
|
||||
|
||||
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
|
||||
Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return Ret;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static char *map_hint = 0;
|
||||
#if defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
// This OS has no flag to enforce allocation below the 4 GB boundary,
|
||||
// but if we hint that we want a low address it is very likely we will
|
||||
// get one.
|
||||
// An older version of this code used MAP_FIXED, but that has the side
|
||||
// effect of discarding already mapped pages that happen to be in the
|
||||
// requested virtual memory range (such as the emulated RAM, sometimes).
|
||||
if (low && (!map_hint))
|
||||
map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
|
||||
#endif
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANON | MAP_PRIVATE
|
||||
#if defined(__x86_64__) && defined(MAP_32BIT)
|
||||
| (low ? MAP_32BIT : 0)
|
||||
#endif
|
||||
, -1, 0);
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
// printf("Mapped executable memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (ptr == MAP_FAILED)
|
||||
{
|
||||
ptr = NULL;
|
||||
#else
|
||||
if (ptr == NULL)
|
||||
{
|
||||
#endif
|
||||
PanicAlert("Failed to allocate executable memory");
|
||||
}
|
||||
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
else
|
||||
{
|
||||
if (low)
|
||||
{
|
||||
map_hint += size;
|
||||
map_hint = (char*)round_page(map_hint); /* round up to the next page */
|
||||
// printf("Next map will (hopefully) be at %p\n", map_hint);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64)
|
||||
if ((u64)ptr >= 0x80000000 && low == true)
|
||||
PanicAlert("Executable memory ended up above 2GB!");
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateMemoryPages(size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
void* ptr = mmap(0, size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
if (ptr == NULL)
|
||||
PanicAlert("Failed to allocate raw memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = _aligned_malloc(size,alignment);
|
||||
#else
|
||||
void* ptr = NULL;
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
;
|
||||
#endif
|
||||
|
||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||
// (unsigned long)size);
|
||||
|
||||
if (ptr == NULL)
|
||||
PanicAlert("Failed to allocate aligned memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* ptr, size_t size)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
||||
ptr = NULL; // Is this our responsibility?
|
||||
|
||||
#else
|
||||
munmap(ptr, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void FreeAlignedMemory(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
_aligned_free(ptr);
|
||||
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
||||
PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
|
||||
PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string MemUsage()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "psapi")
|
||||
DWORD processID = GetCurrentProcessId();
|
||||
HANDLE hProcess;
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
std::string Ret;
|
||||
|
||||
// Print information about the memory usage of the process.
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
|
||||
if (NULL == hProcess) return "MemUsage Error";
|
||||
|
||||
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
|
||||
Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return Ret;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ bool SysConf::SaveToFile(const char *filename)
|
||||
}
|
||||
else if (i->type == Type_SmallArray)
|
||||
{
|
||||
const u8 len = i->dataLength;
|
||||
const u8 len = (u8)(i->dataLength);
|
||||
f.WriteArray(&len, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
virtual void Video_GatherPipeBursted() = 0;
|
||||
|
||||
virtual bool Video_IsPossibleWaitingSetDrawDone() = 0;
|
||||
virtual bool Video_IsHiWatermarkActive() = 0;
|
||||
virtual void Video_AbortFrame() = 0;
|
||||
|
||||
virtual readFn16 Video_CPRead16() = 0;
|
||||
@@ -159,6 +160,7 @@ class VideoBackendHardware : public VideoBackend
|
||||
void Video_GatherPipeBursted();
|
||||
|
||||
bool Video_IsPossibleWaitingSetDrawDone();
|
||||
bool Video_IsHiWatermarkActive();
|
||||
void Video_AbortFrame();
|
||||
|
||||
readFn16 Video_CPRead16();
|
||||
|
||||
@@ -576,7 +576,6 @@
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
<None Include="Src\HW\DSPHLE\UCodes\UCode_Zelda_Obsolete.txt" />
|
||||
<None Include="Src\SConscript" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Externals\Bochs_disasm\Bochs_disasm.vcxproj">
|
||||
|
||||
@@ -1051,7 +1051,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
<None Include="Src\SConscript" />
|
||||
<None Include="Src\HW\DSPHLE\UCodes\UCode_Zelda_Obsolete.txt">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</None>
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
# -*- python -*-
|
||||
|
||||
Import('env')
|
||||
import sys
|
||||
|
||||
files = [
|
||||
'Src/ARDecrypt.cpp',
|
||||
'Src/ActionReplay.cpp',
|
||||
'Src/Boot/Boot.cpp',
|
||||
'Src/Boot/Boot_BS2Emu.cpp',
|
||||
'Src/Boot/Boot_DOL.cpp',
|
||||
'Src/Boot/Boot_ELF.cpp',
|
||||
'Src/Boot/Boot_WiiWAD.cpp',
|
||||
'Src/Boot/ElfReader.cpp',
|
||||
'Src/BootManager.cpp',
|
||||
'Src/ConfigManager.cpp',
|
||||
'Src/Console.cpp',
|
||||
'Src/Core.cpp',
|
||||
'Src/CoreParameter.cpp',
|
||||
'Src/CoreRerecording.cpp',
|
||||
'Src/CoreTiming.cpp',
|
||||
'Src/DSP/DSPAccelerator.cpp',
|
||||
'Src/DSP/DSPAnalyzer.cpp',
|
||||
'Src/DSP/DSPCodeUtil.cpp',
|
||||
'Src/DSP/DSPCore.cpp',
|
||||
'Src/DSP/DSPEmitter.cpp',
|
||||
'Src/DSP/DSPHWInterface.cpp',
|
||||
'Src/DSP/DSPIntCCUtil.cpp',
|
||||
'Src/DSP/DSPIntExtOps.cpp',
|
||||
'Src/DSP/DSPInterpreter.cpp',
|
||||
'Src/DSP/DSPMemoryMap.cpp',
|
||||
'Src/DSP/DSPStacks.cpp',
|
||||
'Src/DSP/DSPTables.cpp',
|
||||
'Src/DSP/DspIntArithmetic.cpp',
|
||||
'Src/DSP/DspIntBranch.cpp',
|
||||
'Src/DSP/DspIntLoadStore.cpp',
|
||||
'Src/DSP/DspIntMisc.cpp',
|
||||
'Src/DSP/DspIntMultiplier.cpp',
|
||||
'Src/DSP/Jit/DSPJitArithmetic.cpp',
|
||||
'Src/DSP/Jit/DSPJitBranch.cpp',
|
||||
'Src/DSP/Jit/DSPJitCCUtil.cpp',
|
||||
'Src/DSP/Jit/DSPJitExtOps.cpp',
|
||||
'Src/DSP/Jit/DSPJitLoadStore.cpp',
|
||||
'Src/DSP/Jit/DSPJitMisc.cpp',
|
||||
'Src/DSP/Jit/DSPJitMultiplier.cpp',
|
||||
'Src/DSP/Jit/DSPJitRegCache.cpp',
|
||||
'Src/DSP/Jit/DSPJitUtil.cpp',
|
||||
'Src/DSP/LabelMap.cpp',
|
||||
'Src/DSP/assemble.cpp',
|
||||
'Src/DSP/disassemble.cpp',
|
||||
'Src/DSPEmulator.cpp',
|
||||
'Src/Debugger/Debugger_SymbolMap.cpp',
|
||||
'Src/Debugger/Dump.cpp',
|
||||
'Src/Debugger/PPCDebugInterface.cpp',
|
||||
'Src/FifoPlayer/FifoAnalyzer.cpp',
|
||||
'Src/FifoPlayer/FifoDataFile.cpp',
|
||||
'Src/FifoPlayer/FifoPlaybackAnalyzer.cpp',
|
||||
'Src/FifoPlayer/FifoPlayer.cpp',
|
||||
'Src/FifoPlayer/FifoRecordAnalyzer.cpp',
|
||||
'Src/FifoPlayer/FifoRecorder.cpp',
|
||||
'Src/GeckoCode.cpp',
|
||||
'Src/GeckoCodeConfig.cpp',
|
||||
'Src/HLE/HLE.cpp',
|
||||
'Src/HLE/HLE_Misc.cpp',
|
||||
'Src/HLE/HLE_OS.cpp',
|
||||
'Src/HW/AudioInterface.cpp',
|
||||
'Src/HW/CPU.cpp',
|
||||
'Src/HW/DSP.cpp',
|
||||
'Src/HW/DSPHLE/DSPHLE.cpp',
|
||||
'Src/HW/DSPHLE/HLEMixer.cpp',
|
||||
'Src/HW/DSPHLE/MailHandler.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_AX.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_CARD.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_GBA.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_ROM.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_Zelda_ADPCM.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_Zelda_Synth.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp',
|
||||
'Src/HW/DSPHLE/UCodes/UCodes.cpp',
|
||||
'Src/HW/DSPLLE/DSPDebugInterface.cpp',
|
||||
'Src/HW/DSPLLE/DSPHost.cpp',
|
||||
'Src/HW/DSPLLE/DSPLLE.cpp',
|
||||
#'Src/HW/DSPLLE/DSPLLEGlobals.cpp',
|
||||
'Src/HW/DSPLLE/DSPLLETools.cpp',
|
||||
'Src/HW/DSPLLE/DSPSymbols.cpp',
|
||||
'Src/HW/DVDInterface.cpp',
|
||||
'Src/HW/EXI.cpp',
|
||||
'Src/HW/EXI_Channel.cpp',
|
||||
'Src/HW/EXI_Device.cpp',
|
||||
'Src/HW/EXI_DeviceAD16.cpp',
|
||||
'Src/HW/EXI_DeviceAMBaseboard.cpp',
|
||||
'Src/HW/EXI_DeviceEthernet.cpp',
|
||||
'Src/HW/EXI_DeviceGecko.cpp',
|
||||
'Src/HW/EXI_DeviceIPL.cpp',
|
||||
'Src/HW/EXI_DeviceMemoryCard.cpp',
|
||||
'Src/HW/EXI_DeviceMic.cpp',
|
||||
'Src/HW/GCMemcard.cpp',
|
||||
'Src/HW/GCPad.cpp',
|
||||
'Src/HW/GCPadEmu.cpp',
|
||||
'Src/HW/GPFifo.cpp',
|
||||
'Src/HW/HW.cpp',
|
||||
'Src/HW/Memmap.cpp',
|
||||
'Src/HW/MemmapFunctions.cpp',
|
||||
'Src/HW/MemoryInterface.cpp',
|
||||
'Src/HW/ProcessorInterface.cpp',
|
||||
'Src/HW/SI.cpp',
|
||||
'Src/HW/SI_Device.cpp',
|
||||
'Src/HW/SI_DeviceAMBaseboard.cpp',
|
||||
'Src/HW/SI_DeviceGBA.cpp',
|
||||
'Src/HW/SI_DeviceGCController.cpp',
|
||||
'Src/HW/Sram.cpp',
|
||||
'Src/HW/StreamADPCM.cpp',
|
||||
'Src/HW/SystemTimers.cpp',
|
||||
'Src/HW/VideoInterface.cpp',
|
||||
'Src/HW/WII_IOB.cpp',
|
||||
'Src/HW/WII_IPC.cpp',
|
||||
'Src/HW/Wiimote.cpp',
|
||||
'Src/HW/WiimoteEmu/Attachment/Attachment.cpp',
|
||||
'Src/HW/WiimoteEmu/Attachment/Classic.cpp',
|
||||
'Src/HW/WiimoteEmu/Attachment/Drums.cpp',
|
||||
'Src/HW/WiimoteEmu/Attachment/Guitar.cpp',
|
||||
'Src/HW/WiimoteEmu/Attachment/Nunchuk.cpp',
|
||||
'Src/HW/WiimoteEmu/Attachment/Turntable.cpp',
|
||||
'Src/HW/WiimoteEmu/EmuSubroutines.cpp',
|
||||
'Src/HW/WiimoteEmu/Encryption.cpp',
|
||||
'Src/HW/WiimoteEmu/Speaker.cpp',
|
||||
'Src/HW/WiimoteEmu/WiimoteEmu.cpp',
|
||||
'Src/HW/WiimoteReal/WiimoteReal.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp',
|
||||
'Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp',
|
||||
'Src/IPC_HLE/WiiMote_HID_Attr.cpp',
|
||||
'Src/MemTools.cpp',
|
||||
'Src/Movie.cpp',
|
||||
'Src/NetPlay.cpp',
|
||||
'Src/NetPlayClient.cpp',
|
||||
'Src/NetPlayServer.cpp',
|
||||
'Src/PatchEngine.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_Branch.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_Integer.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_Paired.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp',
|
||||
'Src/PowerPC/Interpreter/Interpreter_Tables.cpp',
|
||||
'Src/PowerPC/Jit64/Jit.cpp',
|
||||
'Src/PowerPC/Jit64/Jit64_Tables.cpp',
|
||||
'Src/PowerPC/Jit64/JitAsm.cpp',
|
||||
'Src/PowerPC/Jit64/JitRegCache.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_Branch.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_FloatingPoint.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_Integer.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_LoadStore.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_Paired.cpp',
|
||||
'Src/PowerPC/Jit64/Jit_SystemRegisters.cpp',
|
||||
'Src/PowerPC/Jit64IL/IR.cpp',
|
||||
'Src/PowerPC/Jit64IL/IR_X86.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitILAsm.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_Branch.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_FloatingPoint.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_Integer.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_LoadStore.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_LoadStoreFloating.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_LoadStorePaired.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_Paired.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp',
|
||||
'Src/PowerPC/Jit64IL/JitIL_Tables.cpp',
|
||||
'Src/PowerPC/JitCommon/JitAsmCommon.cpp',
|
||||
'Src/PowerPC/JitCommon/JitBackpatch.cpp',
|
||||
'Src/PowerPC/JitCommon/JitBase.cpp',
|
||||
'Src/PowerPC/JitCommon/JitCache.cpp',
|
||||
'Src/PowerPC/JitCommon/Jit_Util.cpp',
|
||||
'Src/PowerPC/LUT_frsqrtex.cpp',
|
||||
'Src/PowerPC/PPCAnalyst.cpp',
|
||||
'Src/PowerPC/PPCCache.cpp',
|
||||
'Src/PowerPC/PPCSymbolDB.cpp',
|
||||
'Src/PowerPC/PPCTables.cpp',
|
||||
'Src/PowerPC/PowerPC.cpp',
|
||||
'Src/PowerPC/Profiler.cpp',
|
||||
'Src/PowerPC/SignatureDB.cpp',
|
||||
'Src/State.cpp',
|
||||
'Src/Tracer.cpp',
|
||||
'Src/VolumeHandler.cpp',
|
||||
]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
files += ['Src/HW/BBA-TAP/TAP_Win32.cpp']
|
||||
files += ['Src/HW/WiimoteReal/IOWin.cpp']
|
||||
files += ['Src/stdafx.cpp']
|
||||
elif sys.platform == 'darwin':
|
||||
files += ['Src/HW/BBA-TAP/TAP_Apple.cpp']
|
||||
files += ['Src/HW/WiimoteReal/IOdarwin.mm']
|
||||
elif sys.platform == 'linux2' and env['HAVE_BLUEZ']:
|
||||
files += ['Src/HW/BBA-TAP/TAP_Unix.cpp']
|
||||
files += ['Src/HW/WiimoteReal/IODummy.cpp']
|
||||
else:
|
||||
files += ['Src/HW/BBA-TAP/TAP_Unix.cpp']
|
||||
files += ['Src/HW/WiimoteReal/IODummy.cpp']
|
||||
|
||||
env['LIBS'] += env.StaticLibrary('core', files)
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "Common.h" // Common
|
||||
#include "StringUtil.h"
|
||||
#include "FileUtil.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
#include "../HLE/HLE.h" // Core
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
@@ -68,13 +69,13 @@ void CBoot::Load_FST(bool _bIsWii)
|
||||
u32 fstSize = VolumeHandler::Read32(0x0428) << shift;
|
||||
u32 maxFstSize = VolumeHandler::Read32(0x042c) << shift;
|
||||
|
||||
u32 arenaHigh = 0x817FFFF4 - maxFstSize;
|
||||
u32 arenaHigh = ROUND_DOWN(0x817FFFFF - maxFstSize, 0x20);
|
||||
Memory::Write_U32(arenaHigh, 0x00000034);
|
||||
|
||||
// load FST
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(arenaHigh), fstOffset, fstSize);
|
||||
Memory::Write_U32(arenaHigh, 0x00000038);
|
||||
Memory::Write_U32(maxFstSize, 0x0000003c);
|
||||
Memory::Write_U32(maxFstSize, 0x0000003c);
|
||||
}
|
||||
|
||||
void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
|
||||
@@ -227,7 +228,9 @@ bool CBoot::BootUp()
|
||||
// setup the map from ISOFile ID
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
|
||||
|
||||
VideoInterface::SetRegionReg((char)VolumeHandler::GetVolume()->GetUniqueID().at(3));
|
||||
std::string unique_id = VolumeHandler::GetVolume()->GetUniqueID();
|
||||
if (unique_id.size() >= 4)
|
||||
VideoInterface::SetRegionReg(unique_id.at(3));
|
||||
|
||||
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
|
||||
|
||||
|
||||
@@ -297,6 +297,7 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
|
||||
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
|
||||
Memory::Write_U32(0x00000000, 0x000030dc); // Time
|
||||
Memory::Write_U32(0x00000000, 0x000030d8); // Time
|
||||
Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
|
||||
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
|
||||
Memory::Write_U32(0x01800000, 0x00003100); // BAT
|
||||
Memory::Write_U32(0x01800000, 0x00003104); // BAT
|
||||
@@ -309,7 +310,7 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
|
||||
Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high
|
||||
Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low
|
||||
Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high
|
||||
Memory::Write_U32(0x00000011, 0x00003138); // Console type
|
||||
Memory::Write_U32(0x00000012, 0x00003138); // Console type
|
||||
// 40 is copied from 88 after running apploader
|
||||
Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4)
|
||||
Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007)
|
||||
|
||||
@@ -34,12 +34,35 @@ bool CBoot::IsElfWii(const char *filename)
|
||||
File::IOFile f(filename, "rb");
|
||||
f.ReadBytes(mem, (size_t)filesize);
|
||||
}
|
||||
|
||||
ElfReader reader(mem);
|
||||
// TODO: Find a more reliable way to distinguish.
|
||||
bool isWii = reader.GetEntryPoint() >= 0x80004000;
|
||||
delete[] mem;
|
||||
|
||||
// Use the same method as the DOL loader uses: search for mfspr from HID4,
|
||||
// which should only be used in Wii ELFs.
|
||||
//
|
||||
// Likely to have some false positives/negatives, patches implementing a
|
||||
// better heuristic are welcome.
|
||||
|
||||
u32 HID4_pattern = 0x7c13fba6;
|
||||
u32 HID4_mask = 0xfc1fffff;
|
||||
ElfReader reader(mem);
|
||||
bool isWii = false;
|
||||
|
||||
for (int i = 0; i < reader.GetNumSections(); ++i)
|
||||
{
|
||||
if (reader.IsCodeSection(i))
|
||||
{
|
||||
for (unsigned int j = 0; j < reader.GetSectionSize(i) / sizeof (u32); ++j)
|
||||
{
|
||||
u32 word = Common::swap32(((u32*)reader.GetSectionDataPtr(i))[j]);
|
||||
if ((word & HID4_mask) == HID4_pattern)
|
||||
{
|
||||
isWii = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] mem;
|
||||
return isWii;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,57 @@
|
||||
#include "VolumeCreator.h"
|
||||
#include "CommonPaths.h"
|
||||
|
||||
static u32 state_checksum(u32 *buf, int len)
|
||||
{
|
||||
u32 checksum = 0;
|
||||
len = len>>2;
|
||||
|
||||
for(int i=0; i<len; i++)
|
||||
{
|
||||
checksum += buf[i];
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
u32 checksum;
|
||||
u8 flags;
|
||||
u8 type;
|
||||
u8 discstate;
|
||||
u8 returnto;
|
||||
u32 unknown[6];
|
||||
} StateFlags;
|
||||
|
||||
bool CBoot::Boot_WiiWAD(const char* _pFilename)
|
||||
{
|
||||
|
||||
std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_STATE);
|
||||
|
||||
if (File::Exists(state_filename))
|
||||
{
|
||||
File::IOFile state_file(state_filename, "r+b");
|
||||
StateFlags state;
|
||||
state_file.ReadBytes(&state, sizeof(StateFlags));
|
||||
|
||||
state.type = 0x03; // TYPE_RETURN
|
||||
state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags)-4);
|
||||
|
||||
state_file.Seek(0, SEEK_SET);
|
||||
state_file.WriteBytes(&state, sizeof(StateFlags));
|
||||
}
|
||||
else
|
||||
{
|
||||
File::CreateFullPath(state_filename);
|
||||
File::IOFile state_file(state_filename, "a+b");
|
||||
StateFlags state;
|
||||
memset(&state,0,sizeof(StateFlags));
|
||||
state.type = 0x03; // TYPE_RETURN
|
||||
state.discstate = 0x01; // DISCSTATE_WII
|
||||
state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags)-4);
|
||||
state_file.WriteBytes(&state, sizeof(StateFlags));
|
||||
}
|
||||
|
||||
const DiscIO::INANDContentLoader& ContentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename);
|
||||
if (!ContentLoader.IsValid())
|
||||
return false;
|
||||
|
||||
@@ -59,7 +59,6 @@ public:
|
||||
bool LoadInto(u32 vaddr);
|
||||
bool LoadSymbols();
|
||||
|
||||
private:
|
||||
int GetNumSegments() const { return (int)(header->e_phnum); }
|
||||
int GetNumSections() const { return (int)(header->e_shnum); }
|
||||
const u8 *GetPtr(int offset) const { return (u8*)base + offset; }
|
||||
@@ -73,6 +72,10 @@ private:
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
bool IsCodeSection(int section) const
|
||||
{
|
||||
return sections[section].sh_type == SHT_PROGBITS;
|
||||
}
|
||||
const u8 *GetSegmentPtr(int segment)
|
||||
{
|
||||
return GetPtr(segments[segment].p_offset);
|
||||
|
||||
@@ -74,9 +74,6 @@ bool BootCore(const std::string& _rFilename)
|
||||
StartUp.bRunCompareServer = false;
|
||||
|
||||
StartUp.hInstance = Host_GetInstance();
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
StartUp.bUseFastMem = true;
|
||||
#endif
|
||||
|
||||
// If for example the ISO file is bad we return here
|
||||
if (!StartUp.AutoSetup(SCoreStartupParameter::BOOT_DEFAULT)) return false;
|
||||
|
||||
@@ -190,6 +190,7 @@ void SConfig::SaveSettings()
|
||||
ini.Set("Display", "RenderWindowWidth", m_LocalCoreStartupParameter.iRenderWindowWidth);
|
||||
ini.Set("Display", "RenderWindowHeight", m_LocalCoreStartupParameter.iRenderWindowHeight);
|
||||
ini.Set("Display", "RenderWindowAutoSize", m_LocalCoreStartupParameter.bRenderWindowAutoSize);
|
||||
ini.Set("Display", "KeepWindowOnTop", m_LocalCoreStartupParameter.bKeepWindowOnTop);
|
||||
ini.Set("Display", "ProgressiveScan", m_LocalCoreStartupParameter.bProgressive);
|
||||
ini.Set("Display", "DisableScreenSaver", m_LocalCoreStartupParameter.bDisableScreenSaver);
|
||||
ini.Set("Display", "ForceNTSCJ", m_LocalCoreStartupParameter.bForceNTSCJ);
|
||||
@@ -319,6 +320,7 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Display", "RenderWindowWidth", &m_LocalCoreStartupParameter.iRenderWindowWidth, 640);
|
||||
ini.Get("Display", "RenderWindowHeight", &m_LocalCoreStartupParameter.iRenderWindowHeight, 480);
|
||||
ini.Get("Display", "RenderWindowAutoSize", &m_LocalCoreStartupParameter.bRenderWindowAutoSize, false);
|
||||
ini.Get("Display", "KeepWindowOnTop", &m_LocalCoreStartupParameter.bKeepWindowOnTop, false);
|
||||
ini.Get("Display", "ProgressiveScan", &m_LocalCoreStartupParameter.bProgressive, false);
|
||||
ini.Get("Display", "DisableScreenSaver", &m_LocalCoreStartupParameter.bDisableScreenSaver, true);
|
||||
ini.Get("Display", "ForceNTSCJ", &m_LocalCoreStartupParameter.bForceNTSCJ, false);
|
||||
|
||||
@@ -129,11 +129,19 @@ void DisplayMessage(const char *message, int time_in_ms)
|
||||
SCoreStartupParameter& _CoreParameter =
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
// Actually displaying non-ASCII could cause things to go pear-shaped
|
||||
for (const char *c = message; *c != '\0'; ++c)
|
||||
if (*c < ' ')
|
||||
return;
|
||||
|
||||
g_video_backend->Video_AddMessage(message, time_in_ms);
|
||||
|
||||
if (_CoreParameter.bRenderToMain &&
|
||||
SConfig::GetInstance().m_InterfaceStatusbar) {
|
||||
Host_UpdateStatusBar(message);
|
||||
} else
|
||||
SConfig::GetInstance().m_InterfaceStatusbar)
|
||||
{
|
||||
Host_UpdateStatusBar(message);
|
||||
}
|
||||
else
|
||||
Host_UpdateTitle(message);
|
||||
}
|
||||
|
||||
@@ -285,8 +293,9 @@ void CpuThread()
|
||||
if (_CoreParameter.bLockThreads)
|
||||
Common::SetCurrentThreadAffinity(1); // Force to first core
|
||||
|
||||
if (_CoreParameter.bUseFastMem)
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
EMM::InstallExceptionHandler(); // Let's run under memory watch
|
||||
#endif
|
||||
|
||||
if (!g_stateFileName.empty())
|
||||
State::LoadAs(g_stateFileName);
|
||||
|
||||
@@ -45,8 +45,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
||||
bEnableFPRF(false),
|
||||
bCPUThread(true), bDSPThread(false), bDSPHLE(true),
|
||||
bSkipIdle(true), bNTSC(false), bForceNTSCJ(false),
|
||||
bHLE_BS2(true), bUseFastMem(false),
|
||||
bLockThreads(false),
|
||||
bHLE_BS2(true), bLockThreads(false),
|
||||
bEnableCheats(false),
|
||||
bMergeBlocks(false),
|
||||
bRunCompareServer(false), bRunCompareClient(false),
|
||||
@@ -57,7 +56,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
||||
bAutoHideCursor(false), bUsePanicHandlers(true),
|
||||
iRenderWindowXPos(-1), iRenderWindowYPos(-1),
|
||||
iRenderWindowWidth(640), iRenderWindowHeight(480),
|
||||
bRenderWindowAutoSize(false),
|
||||
bRenderWindowAutoSize(false), bKeepWindowOnTop(false),
|
||||
bFullscreen(false), bRenderToMain(false),
|
||||
bProgressive(false), bDisableScreenSaver(false),
|
||||
iTheme(0),
|
||||
@@ -127,6 +126,7 @@ bool SCoreStartupParameter::AutoSetup(EBootBS2 _BootBS2)
|
||||
SplitPath(m_strFilename, NULL, NULL, &Extension);
|
||||
if (!strcasecmp(Extension.c_str(), ".gcm") ||
|
||||
!strcasecmp(Extension.c_str(), ".iso") ||
|
||||
!strcasecmp(Extension.c_str(), ".wbfs") ||
|
||||
!strcasecmp(Extension.c_str(), ".ciso") ||
|
||||
!strcasecmp(Extension.c_str(), ".gcz") ||
|
||||
bootDrive)
|
||||
|
||||
@@ -103,7 +103,6 @@ struct SCoreStartupParameter
|
||||
bool bNTSC;
|
||||
bool bForceNTSCJ;
|
||||
bool bHLE_BS2;
|
||||
bool bUseFastMem;
|
||||
bool bLockThreads;
|
||||
bool bEnableCheats;
|
||||
bool bMergeBlocks;
|
||||
@@ -133,7 +132,7 @@ struct SCoreStartupParameter
|
||||
std::string strFullscreenResolution;
|
||||
int iRenderWindowXPos, iRenderWindowYPos;
|
||||
int iRenderWindowWidth, iRenderWindowHeight;
|
||||
bool bRenderWindowAutoSize;
|
||||
bool bRenderWindowAutoSize, bKeepWindowOnTop;
|
||||
bool bFullscreen, bRenderToMain;
|
||||
bool bProgressive, bDisableScreenSaver;
|
||||
|
||||
|
||||
@@ -153,17 +153,17 @@ void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMe
|
||||
const VAT &vtxAttr = cpMem.vtxAttr[vatIndex];
|
||||
|
||||
// Colors
|
||||
const int colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1};
|
||||
const int colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp};
|
||||
const u32 colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1};
|
||||
const u32 colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp};
|
||||
|
||||
const int tcElements[8] =
|
||||
const u32 tcElements[8] =
|
||||
{
|
||||
vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements,
|
||||
vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements,
|
||||
vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements
|
||||
};
|
||||
|
||||
const int tcFormat[8] =
|
||||
const u32 tcFormat[8] =
|
||||
{
|
||||
vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat,
|
||||
vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat,
|
||||
|
||||
@@ -71,10 +71,10 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze
|
||||
|
||||
u32 cmdStart = 0;
|
||||
u32 nextMemUpdate = 0;
|
||||
|
||||
|
||||
// Debugging
|
||||
vector<CmdData> prevCmds;
|
||||
|
||||
|
||||
while (cmdStart < frame.fifoDataSize)
|
||||
{
|
||||
// Add memory updates that have occured before this point in the frame
|
||||
@@ -83,9 +83,9 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze
|
||||
AddMemoryUpdate(frame.memoryUpdates[nextMemUpdate], analyzed);
|
||||
++nextMemUpdate;
|
||||
}
|
||||
|
||||
|
||||
bool wasDrawing = m_DrawingObject;
|
||||
|
||||
|
||||
u32 cmdSize = DecodeCommand(&frame.fifoData[cmdStart]);
|
||||
|
||||
#if (LOG_FIFO_CMDS)
|
||||
@@ -95,7 +95,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze
|
||||
cmdData.size = cmdSize;
|
||||
prevCmds.push_back(cmdData);
|
||||
#endif
|
||||
|
||||
|
||||
// Check for error
|
||||
if (cmdSize == 0)
|
||||
{
|
||||
|
||||
@@ -94,8 +94,9 @@ bool FifoPlayer::Play()
|
||||
if (m_EarlyMemoryUpdates && m_CurrentFrame == m_FrameRangeStart)
|
||||
WriteAllMemoryUpdates();
|
||||
|
||||
WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]);
|
||||
++m_CurrentFrame;
|
||||
WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]);
|
||||
|
||||
++m_CurrentFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ public:
|
||||
u32 GetFrameObjectCount();
|
||||
u32 GetCurrentFrameNum() { return m_CurrentFrame; }
|
||||
|
||||
const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) { return m_FrameInfo[frame]; }
|
||||
|
||||
// Frame range
|
||||
u32 GetFrameRangeStart() { return m_FrameRangeStart; }
|
||||
void SetFrameRangeStart(u32 start);
|
||||
|
||||
@@ -253,9 +253,12 @@ bool RunActiveCodes()
|
||||
|
||||
void RunCodeHandler()
|
||||
{
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats)
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats && active_codes.size() > 0)
|
||||
{
|
||||
if (!code_handler_installed)
|
||||
u8 *gameId = Memory::GetPointer(0x80000000);
|
||||
u8 *wiirdId = Memory::GetPointer(0x80001800);
|
||||
|
||||
if (!code_handler_installed || memcmp(gameId, wiirdId, 6))
|
||||
code_handler_installed = InstallCodeHandler();
|
||||
|
||||
if (code_handler_installed)
|
||||
|
||||
@@ -234,8 +234,8 @@ void Write32(const u32 _Value, const u32 _Address)
|
||||
m_Control.PSTAT = tmpAICtrl.PSTAT;
|
||||
g_LastCPUTime = CoreTiming::GetTicks();
|
||||
|
||||
// Tell Drive Interface to stop streaming
|
||||
if (!tmpAICtrl.PSTAT) DVDInterface::g_bStream = false;
|
||||
// Tell Drive Interface to start/stop streaming
|
||||
DVDInterface::g_bStream = tmpAICtrl.PSTAT;
|
||||
}
|
||||
|
||||
// AI Interrupt
|
||||
@@ -293,6 +293,11 @@ static void GenerateAudioInterrupt()
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
void GenerateAISInterrupt()
|
||||
{
|
||||
GenerateAudioInterrupt();
|
||||
}
|
||||
|
||||
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate)
|
||||
{
|
||||
_AISampleRate = g_AISSampleRate;
|
||||
|
||||
@@ -43,6 +43,8 @@ void Write32(const u32 _iValue, const u32 _iAddress);
|
||||
// Get the audio rates (48000 or 32000 only)
|
||||
unsigned int GetAIDSampleRate();
|
||||
|
||||
void GenerateAISInterrupt();
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -354,7 +354,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||
|
||||
// AI
|
||||
case AUDIO_DMA_BLOCKS_LEFT:
|
||||
_uReturnValue = g_audioDMA.BlocksLeft;
|
||||
_uReturnValue = g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0; // AUDIO_DMA_BLOCKS_LEFT is zero based
|
||||
break;
|
||||
|
||||
case AUDIO_DMA_START_LO:
|
||||
@@ -435,10 +435,10 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
|
||||
if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0;
|
||||
|
||||
// g_ARAM
|
||||
// g_ARAM (line below should be commented out to emulate the DMA wait time)
|
||||
g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero
|
||||
|
||||
// unknown
|
||||
// unknown
|
||||
g_dspState.DSPControl.unk3 = tmpControl.unk3;
|
||||
g_dspState.DSPControl.pad = tmpControl.pad;
|
||||
if (g_dspState.DSPControl.pad != 0)
|
||||
@@ -453,13 +453,30 @@ void Write16(const u16 _Value, const u32 _Address)
|
||||
// ARAM
|
||||
// DMA back and forth between ARAM and RAM
|
||||
case AR_INFO:
|
||||
//PanicAlert("write %x %x", _Value,PowerPC::ppcState.pc);
|
||||
//PanicAlert("AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc);
|
||||
ERROR_LOG(DSPINTERFACE, "AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc);
|
||||
g_ARAM_Info.Hex = _Value;
|
||||
|
||||
// 0x43
|
||||
// Monster Hunter Tri, DKCR
|
||||
|
||||
// 0x43, 0x63:
|
||||
// Rebel Strike, Clone Wars, WWE DOR2, Mario Golf
|
||||
|
||||
// 0x43, 0x64, 0x63
|
||||
// Transworld Surf, Smashing Drive, SSBM, Cel Damage
|
||||
|
||||
// __OSInitAudioSystem sets to 0x43 -> expects 16bit adressing and mapping to dsp iram?
|
||||
// __OSCheckSize sets = 0x20 | 3 (keeps upper bits)
|
||||
// 0x23 -> Zelda standard mode (standard ARAM access ??)
|
||||
// 0x43 -> Set by Eternal Darkness and SSBB
|
||||
// 0x43 -> Set by __OSInitAudioSystem
|
||||
// 0x58 -> Transworld Surf, Cel Damage, SSBM
|
||||
// 0x60 -> Transworld Surf, Cel Damage, SSBM
|
||||
// 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ??
|
||||
// 0x64 -> Transworld Surf, Cel Damage, SSBM
|
||||
|
||||
// 0x00 -> Switch to external ARAM
|
||||
// 0x04 -> Switch to internal ARAM
|
||||
break;
|
||||
|
||||
case AR_MODE:
|
||||
@@ -620,7 +637,7 @@ void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet)
|
||||
switch (type)
|
||||
{
|
||||
case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break;
|
||||
case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break;
|
||||
case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; if (_bSet) g_dspState.DSPControl.DMAState = 0; break;
|
||||
case INT_AID: g_dspState.DSPControl.AID = _bSet ? 1 : 0; break;
|
||||
}
|
||||
|
||||
@@ -672,7 +689,7 @@ void UpdateAudioDMA()
|
||||
{
|
||||
// Send silence. Yeah, it's a bit of a waste to sample rate convert
|
||||
// silence. or hm. Maybe we shouldn't do this :)
|
||||
// dsp->DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
|
||||
//dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,44 +699,95 @@ void Do_ARAM_DMA()
|
||||
// seems like a good estimate
|
||||
CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
|
||||
|
||||
// Uncomment the line below to emulate the DMA wait time.
|
||||
//g_dspState.DSPControl.DMAState = 1;
|
||||
|
||||
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
|
||||
if (g_arDMA.Cnt.dir)
|
||||
{
|
||||
// ARAM -> MRAM
|
||||
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x",
|
||||
g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr);
|
||||
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x PC: %08x",
|
||||
g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr, PC);
|
||||
|
||||
while (g_arDMA.Cnt.count)
|
||||
// Outgoing data from ARAM is mirrored every 64MB (verified on real HW)
|
||||
g_arDMA.ARAddr &= 0x3ffffff;
|
||||
g_arDMA.MMAddr &= 0x3ffffff;
|
||||
|
||||
if (g_arDMA.ARAddr < g_ARAM.size)
|
||||
{
|
||||
if (g_arDMA.ARAddr < g_ARAM.size)
|
||||
while (g_arDMA.Cnt.count)
|
||||
{
|
||||
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr], g_arDMA.MMAddr);
|
||||
if ((g_ARAM_Info.Hex & 0xf) == 3)
|
||||
{
|
||||
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
|
||||
}
|
||||
else if ((g_ARAM_Info.Hex & 0xf) == 4)
|
||||
{
|
||||
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
|
||||
}
|
||||
else
|
||||
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
|
||||
g_arDMA.MMAddr += 8;
|
||||
g_arDMA.ARAddr += 8;
|
||||
g_arDMA.Cnt.count -= 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assuming no external ARAM installed; returns zeroes on out of bounds reads (verified on real HW)
|
||||
while (g_arDMA.Cnt.count)
|
||||
{
|
||||
Memory::Write_U64(0, g_arDMA.MMAddr);
|
||||
g_arDMA.MMAddr += 8;
|
||||
g_arDMA.ARAddr += 8;
|
||||
g_arDMA.Cnt.count -= 8;
|
||||
}
|
||||
g_arDMA.Cnt.count -= 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// MRAM -> ARAM
|
||||
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x",
|
||||
g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr);
|
||||
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x PC: %08x",
|
||||
g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr, PC);
|
||||
|
||||
while (g_arDMA.Cnt.count)
|
||||
// Incoming data into ARAM is mirrored every 64MB (verified on real HW)
|
||||
g_arDMA.ARAddr &= 0x3ffffff;
|
||||
g_arDMA.MMAddr &= 0x3ffffff;
|
||||
|
||||
if (g_arDMA.ARAddr < g_ARAM.size)
|
||||
{
|
||||
if (g_arDMA.ARAddr < g_ARAM.size)
|
||||
while (g_arDMA.Cnt.count)
|
||||
{
|
||||
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
|
||||
if ((g_ARAM_Info.Hex & 0xf) == 3)
|
||||
{
|
||||
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
|
||||
}
|
||||
else if ((g_ARAM_Info.Hex & 0xf) == 4)
|
||||
{
|
||||
if (g_arDMA.ARAddr < 0x400000)
|
||||
{
|
||||
*(u64*)&g_ARAM.ptr[(g_arDMA.ARAddr + 0x400000) & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
|
||||
}
|
||||
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
|
||||
}
|
||||
else
|
||||
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
|
||||
|
||||
g_arDMA.MMAddr += 8;
|
||||
g_arDMA.ARAddr += 8;
|
||||
g_arDMA.Cnt.count -= 8;
|
||||
}
|
||||
g_arDMA.Cnt.count -= 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assuming no external ARAM installed; writes nothing to ARAM when out of bounds (verified on real HW)
|
||||
g_arDMA.MMAddr += g_arDMA.Cnt.count;
|
||||
g_arDMA.ARAddr += g_arDMA.Cnt.count;
|
||||
g_arDMA.Cnt.count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// (shuffle2) I still don't believe that this hack is actually needed... :(
|
||||
// Maybe the wii sports ucode is processed incorrectly?
|
||||
// (LM) It just means that dsp reads via '0xffdd' on WII can end up in EXRAM or main RAM
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "Thread.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "IniFile.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "CPUDetect.h"
|
||||
|
||||
#include "DSPLLEGlobals.h" // Local
|
||||
#include "DSP/DSPInterpreter.h"
|
||||
@@ -84,6 +86,27 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle)
|
||||
{
|
||||
Common::SetCurrentThreadName("DSP thread");
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bLockThreads)
|
||||
{
|
||||
if (cpu_info.num_cores > 3)
|
||||
{
|
||||
// HACK (delroth): there is no way to know where hyperthreads are in
|
||||
// the current Dolphin version.
|
||||
bool windows = false;
|
||||
#ifdef _WIN32
|
||||
windows = true;
|
||||
#endif
|
||||
|
||||
u8 core_id;
|
||||
if (windows && cpu_info.num_cores > 4) // Probably HT
|
||||
core_id = 5; // 3rd non HT core
|
||||
else
|
||||
core_id = 3; // 3rd core
|
||||
|
||||
Common::SetCurrentThreadAffinity(1 << core_id);
|
||||
}
|
||||
}
|
||||
|
||||
while (dsp_lle->m_bIsRunning)
|
||||
{
|
||||
int cycles = (int)dsp_lle->m_cycle_count;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "Thread.h"
|
||||
#include "Memmap.h"
|
||||
#include "../VolumeHandler.h"
|
||||
#include "AudioInterface.h"
|
||||
|
||||
// Disc transfer rate measured in bytes per second
|
||||
static const u32 DISC_TRANSFER_RATE_GC = 3125 * 1024;
|
||||
@@ -201,9 +202,11 @@ static UDICR m_DICR;
|
||||
static UDIIMMBUF m_DIIMMBUF;
|
||||
static UDICFG m_DICFG;
|
||||
|
||||
static u32 AudioStart;
|
||||
static u32 LoopStart;
|
||||
static u32 AudioPos;
|
||||
static u32 AudioLength;
|
||||
static u32 CurrentStart;
|
||||
static u32 LoopLength;
|
||||
static u32 CurrentLength;
|
||||
|
||||
u32 g_ErrorCode = 0;
|
||||
bool g_bDiscInside = false;
|
||||
@@ -238,12 +241,16 @@ void DoState(PointerWrap &p)
|
||||
p.Do(m_DIIMMBUF);
|
||||
p.Do(m_DICFG);
|
||||
|
||||
p.Do(AudioStart);
|
||||
p.Do(LoopStart);
|
||||
p.Do(AudioPos);
|
||||
p.Do(AudioLength);
|
||||
p.Do(LoopLength);
|
||||
|
||||
p.Do(g_ErrorCode);
|
||||
p.Do(g_bDiscInside);
|
||||
p.Do(g_bStream);
|
||||
|
||||
p.Do(CurrentStart);
|
||||
p.Do(CurrentLength);
|
||||
}
|
||||
|
||||
void TransferComplete(u64 userdata, int cyclesLate)
|
||||
@@ -266,9 +273,13 @@ void Init()
|
||||
m_DICFG.Hex = 0;
|
||||
m_DICFG.CONFIG = 1; // Disable bootrom descrambler
|
||||
|
||||
AudioStart = 0;
|
||||
AudioPos = 0;
|
||||
AudioLength = 0;
|
||||
AudioPos = 0;
|
||||
LoopStart = 0;
|
||||
LoopLength = 0;
|
||||
CurrentStart = 0;
|
||||
CurrentLength = 0;
|
||||
|
||||
g_bStream = false;
|
||||
|
||||
ejectDisc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
|
||||
insertDisc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
|
||||
@@ -351,33 +362,46 @@ bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength)
|
||||
|
||||
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples)
|
||||
{
|
||||
_iNumSamples &= ~31;
|
||||
|
||||
if (AudioPos == 0)
|
||||
{
|
||||
//MessageBox(0,"DVD: Trying to stream from 0", "bah", 0);
|
||||
memset(_pDestBuffer, 0, _iNumSamples); // probably __AI_SRC_INIT :P
|
||||
return false;
|
||||
}
|
||||
_iNumSamples &= ~31;
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(dvdread_section);
|
||||
VolumeHandler::ReadToPtr(_pDestBuffer, AudioPos, _iNumSamples);
|
||||
std::lock_guard<std::mutex> lk(dvdread_section);
|
||||
VolumeHandler::ReadToPtr(_pDestBuffer, AudioPos, _iNumSamples);
|
||||
}
|
||||
|
||||
//
|
||||
// FIX THIS
|
||||
//
|
||||
// loop check
|
||||
//
|
||||
AudioPos += _iNumSamples;
|
||||
if (AudioPos >= AudioStart + AudioLength)
|
||||
if (g_bStream)
|
||||
{
|
||||
g_bStream = false; // Starfox Adventures
|
||||
AudioPos = AudioStart;
|
||||
NGCADPCM::InitFilter();
|
||||
}
|
||||
AudioPos += _iNumSamples;
|
||||
|
||||
//WARN_LOG(DVDINTERFACE,"ReadADPCM");
|
||||
return true;
|
||||
if (AudioPos >= CurrentStart + CurrentLength)
|
||||
{
|
||||
if (LoopStart == 0)
|
||||
{
|
||||
AudioPos = 0;
|
||||
CurrentStart = 0;
|
||||
CurrentLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
AudioPos = LoopStart;
|
||||
CurrentStart = LoopStart;
|
||||
CurrentLength = LoopLength;
|
||||
}
|
||||
NGCADPCM::InitFilter();
|
||||
AudioInterface::GenerateAISInterrupt();
|
||||
}
|
||||
|
||||
//WARN_LOG(DVDINTERFACE,"ReadADPCM");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||
@@ -813,28 +837,69 @@ void ExecuteCommand(UDICR& _DICR)
|
||||
// m_DICMDBUF[2].Hex = Length of the stream
|
||||
case 0xE1:
|
||||
{
|
||||
// ugly hack to catch the disable command
|
||||
if (m_DICMDBUF[1].Hex != 0)
|
||||
u32 pos = m_DICMDBUF[1].Hex << 2;
|
||||
u32 length = m_DICMDBUF[2].Hex;
|
||||
|
||||
// Start playing
|
||||
if (!g_bStream && m_DICMDBUF[0].CMDBYTE1 == 0 && pos != 0 && length != 0)
|
||||
{
|
||||
AudioPos = m_DICMDBUF[1].Hex << 2;
|
||||
AudioStart = AudioPos;
|
||||
AudioLength = m_DICMDBUF[2].Hex;
|
||||
NGCADPCM::InitFilter();
|
||||
|
||||
AudioPos = pos;
|
||||
CurrentStart = pos;
|
||||
CurrentLength = length;
|
||||
NGCADPCM::InitFilter();
|
||||
g_bStream = true;
|
||||
|
||||
WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %02x offset = %08x length=%08x",
|
||||
m_DICMDBUF[0].CMDBYTE1, AudioPos, AudioLength);
|
||||
}
|
||||
else
|
||||
WARN_LOG(DVDINTERFACE, "(Audio) Off?");
|
||||
|
||||
LoopStart = pos;
|
||||
LoopLength = length;
|
||||
g_bStream = (m_DICMDBUF[0].CMDBYTE1 == 0); // This command can start/stop the stream
|
||||
|
||||
// Stop stream
|
||||
if (m_DICMDBUF[0].CMDBYTE1 == 1)
|
||||
{
|
||||
AudioPos = 0;
|
||||
LoopStart = 0;
|
||||
LoopLength = 0;
|
||||
CurrentStart = 0;
|
||||
CurrentLength = 0;
|
||||
}
|
||||
|
||||
WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %08x offset = %08x length=%08x",
|
||||
m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex << 2, m_DICMDBUF[2].Hex);
|
||||
}
|
||||
break;
|
||||
|
||||
// Request Audio Status (Immediate)
|
||||
case 0xE2:
|
||||
m_DIIMMBUF.Hex = g_bStream ? 1 : 0;
|
||||
//WARN_LOG(DVDINTERFACE, "(Audio): Request Audio status %s", g_bStream? "on":"off");
|
||||
{
|
||||
switch (m_DICMDBUF[0].CMDBYTE1)
|
||||
{
|
||||
case 0x00: // Returns streaming status
|
||||
m_DIIMMBUF.Hex = (AudioPos == 0) ? 0 : 1;
|
||||
break;
|
||||
case 0x01: // Returns the current offset
|
||||
if (g_bStream)
|
||||
m_DIIMMBUF.Hex = (AudioPos - CurrentStart) >> 2;
|
||||
else
|
||||
m_DIIMMBUF.Hex = 0;
|
||||
break;
|
||||
case 0x02: // Returns the start offset
|
||||
if (g_bStream)
|
||||
m_DIIMMBUF.Hex = CurrentStart >> 2;
|
||||
else
|
||||
m_DIIMMBUF.Hex = 0;
|
||||
break;
|
||||
case 0x03: // Returns the total length
|
||||
if (g_bStream)
|
||||
m_DIIMMBUF.Hex = CurrentLength;
|
||||
else
|
||||
m_DIIMMBUF.Hex = 0;
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", m_DICMDBUF[0].CMDBYTE1, g_bStream? "on":"off");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DVDLowStopMotor:
|
||||
|
||||
@@ -109,7 +109,7 @@ CEXIIPL::CEXIIPL() :
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHLE_BS2)
|
||||
{
|
||||
// Copy header
|
||||
memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, sizeof(m_bNTSC ? iplverNTSC : iplverPAL));
|
||||
memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, m_bNTSC ? sizeof(iplverNTSC) : sizeof(iplverPAL));
|
||||
|
||||
// Load fonts
|
||||
LoadFileToIPL((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_SJIS), 0x1aff00);
|
||||
@@ -197,7 +197,7 @@ void CEXIIPL::TransferByte(u8& _uByte)
|
||||
|
||||
// The first 4 bytes must be the address
|
||||
// If we haven't read it, do it now
|
||||
if (m_uPosition < 4)
|
||||
if (m_uPosition <= 3)
|
||||
{
|
||||
m_uAddress <<= 8;
|
||||
m_uAddress |= _uByte;
|
||||
@@ -207,137 +207,156 @@ void CEXIIPL::TransferByte(u8& _uByte)
|
||||
// Check if the command is complete
|
||||
if (m_uPosition == 3)
|
||||
{
|
||||
// Get the time ...
|
||||
// Get the time ...
|
||||
u32 &rtc = *((u32 *)&m_RTC);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||
*((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime() - cWiiBias); // Subtract Wii bias
|
||||
{
|
||||
// Subtract Wii bias
|
||||
rtc = Common::swap32(CEXIIPL::GetGCTime() - cWiiBias);
|
||||
}
|
||||
else
|
||||
*((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime());
|
||||
{
|
||||
rtc = Common::swap32(CEXIIPL::GetGCTime());
|
||||
}
|
||||
|
||||
#if MAX_LOGLEVEL >= INFO_LEVEL
|
||||
|
||||
if ((m_uAddress & 0xF0000000) == 0xb0000000)
|
||||
// Log the command
|
||||
std::string device_name;
|
||||
|
||||
switch (CommandRegion())
|
||||
{
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something");
|
||||
case REGION_RTC:
|
||||
device_name = "RTC";
|
||||
break;
|
||||
case REGION_SRAM:
|
||||
device_name = "SRAM";
|
||||
break;
|
||||
case REGION_UART:
|
||||
device_name = "UART";
|
||||
break;
|
||||
case REGION_EUART:
|
||||
case REGION_EUART_UNK:
|
||||
device_name = "EUART";
|
||||
break;
|
||||
case REGION_UART_UNK:
|
||||
device_name = "UART Other?";
|
||||
break;
|
||||
case REGION_BARNACLE:
|
||||
device_name = "UART Barnacle";
|
||||
break;
|
||||
case REGION_WRTC0:
|
||||
case REGION_WRTC1:
|
||||
case REGION_WRTC2:
|
||||
device_name = "Wii RTC flags - not implemented";
|
||||
break;
|
||||
default:
|
||||
if ((m_uAddress >> 6) < ROM_SIZE)
|
||||
{
|
||||
device_name = "ROM";
|
||||
}
|
||||
else
|
||||
{
|
||||
device_name = "illegal address";
|
||||
_dbg_assert_msg_(EXPANSIONINTERFACE, 0,
|
||||
"EXI IPL-DEV: %s %08x", device_name.c_str(), m_uAddress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if ((m_uAddress & 0xF0000000) == 0x30000000)
|
||||
{
|
||||
// wii stuff perhaps wii SRAM?
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something (perhaps SRAM?)");
|
||||
}
|
||||
else if ((m_uAddress & 0x60000000) == 0)
|
||||
{
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: IPL access");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
||||
{
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC access");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
||||
{
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: SRAM access");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
||||
{
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20011300)
|
||||
{
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART Barnacle");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010300)
|
||||
{
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART Other?");
|
||||
}
|
||||
else if (((m_uAddress & 0x7FFFFF00) == 0x21000000) ||
|
||||
((m_uAddress & 0x7FFFFF00) == 0x21000100) ||
|
||||
((m_uAddress & 0x7FFFFF00) == 0x21000800))
|
||||
{
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC flags (WII only) - not implemented");
|
||||
}
|
||||
else
|
||||
{
|
||||
//_dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||
_dbg_assert_msg_(EXPANSIONINTERFACE, 0, "EXI IPL-DEV: illegal access address %08x", m_uAddress);
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: illegal address %08x", m_uAddress);
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "%s %s %08x", device_name.c_str(),
|
||||
IsWriteCommand() ? "write" : "read", m_uAddress);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// --- Encrypted ROM ---
|
||||
// atm we pre-decrypt the whole thing, see CEXIIPL ctor
|
||||
if ((m_uAddress & 0x60000000) == 0)
|
||||
// Actually read or write a byte
|
||||
switch (CommandRegion())
|
||||
{
|
||||
if ((m_uAddress & 0x80000000) == 0)
|
||||
{
|
||||
u32 position = ((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset;
|
||||
|
||||
// Technically we should apply descrambling here, if it's currently enabled.
|
||||
_uByte = m_pIPL[position];
|
||||
|
||||
if ((position >= 0x001AFF00) && (position <= 0x001FF474) && !m_FontsLoaded)
|
||||
{
|
||||
PanicAlertT("Error: Trying to access %s fonts but they are not loaded. Games may not show fonts correctly, or crash.",
|
||||
(position >= 0x001FCF00)?"ANSI":"SJIS");
|
||||
m_FontsLoaded = true; // Don't be a nag :p
|
||||
}
|
||||
}
|
||||
}
|
||||
// --- Real Time Clock (RTC) ---
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
||||
{
|
||||
if (m_uAddress & 0x80000000)
|
||||
case REGION_RTC:
|
||||
if (IsWriteCommand())
|
||||
m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte;
|
||||
else
|
||||
_uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset];
|
||||
}
|
||||
// --- SRAM ---
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
||||
{
|
||||
if (m_uAddress & 0x80000000)
|
||||
break;
|
||||
|
||||
case REGION_SRAM:
|
||||
if (IsWriteCommand())
|
||||
g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte;
|
||||
else
|
||||
_uByte = g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset];
|
||||
}
|
||||
// --- UART ---
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
||||
{
|
||||
if (m_uAddress & 0x80000000)
|
||||
break;
|
||||
|
||||
case REGION_UART:
|
||||
case REGION_EUART:
|
||||
if (IsWriteCommand())
|
||||
{
|
||||
m_szBuffer[m_count++] = _uByte;
|
||||
if (_uByte != '\0')
|
||||
m_szBuffer[m_count++] = _uByte;
|
||||
if ((m_count >= 256) || (_uByte == 0xD))
|
||||
{
|
||||
m_szBuffer[m_count] = 0x00;
|
||||
INFO_LOG(OSREPORT, "%s", m_szBuffer);
|
||||
NOTICE_LOG(OSREPORT, "%s", m_szBuffer);
|
||||
memset(m_szBuffer, 0, sizeof(m_szBuffer));
|
||||
m_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
_uByte = 0x01; // dunno
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20011300)
|
||||
{
|
||||
INFO_LOG(OSREPORT, "UART Barnacle %x", _uByte);
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010300)
|
||||
{
|
||||
INFO_LOG(OSREPORT, "UART? %x", _uByte);
|
||||
{
|
||||
// "Queue Length"... return 0 cause we're instant
|
||||
_uByte = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case REGION_EUART_UNK:
|
||||
// Writes 0xf2 then 0xf3 on EUART init. Just need to return non-zero
|
||||
// so we can leave the byte untouched.
|
||||
break;
|
||||
|
||||
case REGION_UART_UNK:
|
||||
DEBUG_LOG(OSREPORT, "UART? %x", _uByte);
|
||||
_uByte = 0xff;
|
||||
break;
|
||||
|
||||
case REGION_BARNACLE:
|
||||
DEBUG_LOG(OSREPORT, "UART Barnacle %x", _uByte);
|
||||
break;
|
||||
|
||||
case REGION_WRTC0:
|
||||
case REGION_WRTC1:
|
||||
case REGION_WRTC2:
|
||||
// WII only RTC flags... afaik just the wii menu initialize it
|
||||
default:
|
||||
if ((m_uAddress >> 6) < ROM_SIZE)
|
||||
{
|
||||
if (!IsWriteCommand())
|
||||
{
|
||||
u32 position = ((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset;
|
||||
|
||||
// Technically we should descramble here iff descrambling logic is enabled.
|
||||
// At the moment, we pre-decrypt the whole thing and
|
||||
// ignore the "enabled" bit - see CEXIIPL::CEXIIPL
|
||||
_uByte = m_pIPL[position];
|
||||
|
||||
if ((position >= 0x001AFF00) && (position <= 0x001FF474) && !m_FontsLoaded)
|
||||
{
|
||||
PanicAlertT(
|
||||
"Error: Trying to access %s fonts but they are not loaded. "
|
||||
"Games may not show fonts correctly, or crash.",
|
||||
(position >= 0x001FCF00) ? "ANSI" : "SJIS");
|
||||
m_FontsLoaded = true; // Don't be a nag :p
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NOTICE_LOG(OSREPORT, "EXI IPL-DEV: %s %x at %08x",
|
||||
IsWriteCommand() ? "write" : "read", _uByte, m_uAddress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (((m_uAddress & 0x7FFFFF00) == 0x21000000) ||
|
||||
((m_uAddress & 0x7FFFFF00) == 0x21000100) ||
|
||||
((m_uAddress & 0x7FFFFF00) == 0x21000800))
|
||||
{
|
||||
// WII only RTC flags... afaik just the wii menu initialize it
|
||||
// if (m_uAddress & 0x80000000)
|
||||
// g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte;
|
||||
// else
|
||||
// _uByte = g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset];
|
||||
}
|
||||
|
||||
m_uRWOffset++;
|
||||
}
|
||||
|
||||
m_uPosition++;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,20 @@ private:
|
||||
ROM_MASK = (ROM_SIZE - 1)
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
REGION_RTC = 0x200000,
|
||||
REGION_SRAM = 0x200001,
|
||||
REGION_UART = 0x200100,
|
||||
REGION_UART_UNK = 0x200103,
|
||||
REGION_BARNACLE = 0x200113,
|
||||
REGION_WRTC0 = 0x210000,
|
||||
REGION_WRTC1 = 0x210001,
|
||||
REGION_WRTC2 = 0x210008,
|
||||
REGION_EUART_UNK= 0x300000,
|
||||
REGION_EUART = 0x300001
|
||||
};
|
||||
|
||||
// Region
|
||||
bool m_bNTSC;
|
||||
|
||||
@@ -63,6 +77,8 @@ private:
|
||||
bool m_FontsLoaded;
|
||||
|
||||
virtual void TransferByte(u8 &_uByte);
|
||||
bool IsWriteCommand() const { return !!(m_uAddress & (1 << 31)); }
|
||||
u32 const CommandRegion() const { return (m_uAddress & ~(1 << 31)) >> 8; }
|
||||
|
||||
void LoadFileToIPL(std::string filename, u32 offset);
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
||||
|
||||
void innerFlush(FlushData* data)
|
||||
{
|
||||
File::IOFile pFile(data->filename, "wb");
|
||||
File::IOFile pFile(data->filename, "r+b");
|
||||
if (!pFile)
|
||||
{
|
||||
std::string dir;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,14 +19,15 @@
|
||||
#define __GCMEMCARD_h__
|
||||
|
||||
#include "Common.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "Sram.h"
|
||||
#include "StringUtil.h"
|
||||
#include "EXI_DeviceIPL.h"
|
||||
|
||||
#define BE64(x) (Common::swap64(x))
|
||||
#define BE32(x) (Common::swap32(x))
|
||||
#define BE16(x) (Common::swap16(x))
|
||||
#define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8)));
|
||||
|
||||
enum
|
||||
{
|
||||
SLOT_A = 0,
|
||||
@@ -54,6 +55,7 @@ enum
|
||||
DENTRY_STRLEN = 0x20,
|
||||
DENTRY_SIZE = 0x40,
|
||||
BLOCK_SIZE = 0x2000,
|
||||
BAT_SIZE = 0xFFB,
|
||||
|
||||
MemCard59Mb = 0x04,
|
||||
MemCard123Mb = 0x08,
|
||||
@@ -75,25 +77,28 @@ private:
|
||||
std::string m_fileName;
|
||||
|
||||
u32 maxBlock;
|
||||
u32 mc_data_size;
|
||||
u8* mc_data;
|
||||
|
||||
u16 m_sizeMb;
|
||||
|
||||
struct GCMBlock
|
||||
{
|
||||
GCMBlock(){erase();}
|
||||
void erase() {memset(block, 0xFF, BLOCK_SIZE);}
|
||||
u8 block[BLOCK_SIZE];
|
||||
};
|
||||
std::vector<GCMBlock> mc_data_blocks;
|
||||
#pragma pack(push,1)
|
||||
struct Header { //Offset Size Description
|
||||
// Serial in libogc
|
||||
u8 serial[12]; //0x0000 12 ?
|
||||
u64 formatTime; //0x000c 8 time of format (OSTime value)
|
||||
u8 SramBias[4]; //0x0014 4 sram bias at time of format
|
||||
u8 SramLang[4]; //0x0018 4 sram language
|
||||
u32 SramBias; //0x0014 4 sram bias at time of format
|
||||
u32 SramLang; //0x0018 4 sram language
|
||||
u8 Unk2[4]; //0x001c 4 ? almost always 0
|
||||
// end Serial in libogc
|
||||
u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B
|
||||
u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits
|
||||
u16 Encoding; //0x0024 2 encoding (ASCII or japanese)
|
||||
u8 Unused1[468]; //0x0026 468 unused (0xff)
|
||||
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
|
||||
u16 UpdateCounter; //0x01fa 2 update Counter (?, probably unused)
|
||||
u16 Checksum; //0x01fc 2 Additive Checksum
|
||||
u16 Checksum_Inv; //0x01fe 2 Inverse Checksum
|
||||
u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff)
|
||||
@@ -101,7 +106,7 @@ private:
|
||||
|
||||
struct DEntry {
|
||||
u8 Gamecode[4]; //0x00 0x04 Gamecode
|
||||
u8 Markercode[2]; //0x04 0x02 Makercode
|
||||
u8 Makercode[2]; //0x04 0x02 Makercode
|
||||
u8 Unused1; //0x06 0x01 reserved/unused (always 0xff, has no effect)
|
||||
u8 BIFlags; //0x07 0x01 banner gfx format and icon animation (Image Key)
|
||||
// bit(s) description
|
||||
@@ -147,19 +152,25 @@ private:
|
||||
struct Directory {
|
||||
DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127)
|
||||
u8 Padding[0x3a];
|
||||
u8 UpdateCounter[2];//0x1ffa 2 update Counter
|
||||
u16 UpdateCounter; //0x1ffa 2 update Counter
|
||||
u16 Checksum; //0x1ffc 2 Additive Checksum
|
||||
u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum
|
||||
} dir, dir_backup;
|
||||
|
||||
Directory *CurrentDir, *PreviousDir;
|
||||
struct BlockAlloc {
|
||||
u16 Checksum; //0x0000 2 Additive Checksum
|
||||
u16 Checksum_Inv; //0x0002 2 Inverse Checksum
|
||||
u8 UpdateCounter[2];//0x0004 2 update Counter
|
||||
u8 FreeBlocks[2]; //0x0006 2 free Blocks
|
||||
u8 LastAllocated[2];//0x0008 2 last allocated Block
|
||||
u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks
|
||||
u16 Checksum; //0x0000 2 Additive Checksum
|
||||
u16 Checksum_Inv; //0x0002 2 Inverse Checksum
|
||||
u16 UpdateCounter; //0x0004 2 update Counter
|
||||
u16 FreeBlocks; //0x0006 2 free Blocks
|
||||
u16 LastAllocated; //0x0008 2 last allocated Block
|
||||
u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks
|
||||
u16 GetNextBlock(u16 Block) const;
|
||||
u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const;
|
||||
bool ClearBlocks(u16 StartingBlock, u16 Length);
|
||||
} bat,bat_backup;
|
||||
|
||||
BlockAlloc *CurrentBat, *PreviousBat;
|
||||
struct GCMC_Header
|
||||
{
|
||||
Header *hdr;
|
||||
@@ -168,92 +179,83 @@ private:
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile);
|
||||
u32 ImportGciInternal(FILE* gcih, const char *inputFile, const std::string &outputFile);
|
||||
static void FormatInternal(GCMC_Header &GCP);
|
||||
public:
|
||||
|
||||
GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false);
|
||||
bool IsValid() { return m_valid; }
|
||||
bool IsAsciiEncoding();
|
||||
bool IsValid() const { return m_valid; }
|
||||
bool IsAsciiEncoding() const;
|
||||
bool Save();
|
||||
bool Format(bool sjis = false, u16 SizeMb = MemCard2043Mb);
|
||||
static bool Format(u8 * card_data, bool sjis = false, u16 SizeMb = MemCard2043Mb);
|
||||
|
||||
static void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum);
|
||||
u32 TestChecksums();
|
||||
u32 TestChecksums() const;
|
||||
bool FixChecksums();
|
||||
|
||||
// get number of file entries in the directory
|
||||
u8 GetNumFiles();
|
||||
u8 GetNumFiles() const;
|
||||
u8 GetFileIndex(u8 fileNumber) const;
|
||||
|
||||
// get the free blocks from bat
|
||||
u16 GetFreeBlocks();
|
||||
u16 GetFreeBlocks() const;
|
||||
|
||||
// If title already on memcard returns index, otherwise returns -1
|
||||
u8 TitlePresent(DEntry d);
|
||||
|
||||
// DEntry functions, all take u8 index < DIRLEN (127)
|
||||
// Functions that have ascii output take a char *buffer
|
||||
u8 TitlePresent(DEntry d) const;
|
||||
|
||||
// buffer needs to be a char[5] or bigger
|
||||
bool DEntry_GameCode(u8 index, char *buffer);
|
||||
// buffer needs to be a char[2] or bigger
|
||||
bool DEntry_Markercode(u8 index, char *buffer);
|
||||
// buffer needs to be a char[9] or bigger
|
||||
bool DEntry_BIFlags(u8 index, char *buffer);
|
||||
// buffer needs to be a char[32] or bigger
|
||||
bool DEntry_FileName(u8 index, char *buffer);
|
||||
u32 DEntry_ModTime(u8 index);
|
||||
u32 DEntry_ImageOffset(u8 index);
|
||||
// buffer needs to be a char[17] or bigger
|
||||
bool DEntry_IconFmt(u8 index, char *buffer);
|
||||
u16 DEntry_AnimSpeed(u8 index);
|
||||
// buffer needs to be a char[4] or bigger
|
||||
bool DEntry_Permissions(u8 index, char *buffer);
|
||||
u8 DEntry_CopyCounter(u8 index);
|
||||
bool GCI_FileName(u8 index, std::string &filename) const;
|
||||
// DEntry functions, all take u8 index < DIRLEN (127)
|
||||
std::string DEntry_GameCode(u8 index) const;
|
||||
std::string DEntry_Makercode(u8 index) const;
|
||||
std::string DEntry_BIFlags(u8 index) const;
|
||||
std::string DEntry_FileName(u8 index) const;
|
||||
u32 DEntry_ModTime(u8 index) const;
|
||||
u32 DEntry_ImageOffset(u8 index) const;
|
||||
std::string DEntry_IconFmt(u8 index) const;
|
||||
u16 DEntry_AnimSpeed(u8 index) const;
|
||||
std::string DEntry_Permissions(u8 index) const;
|
||||
u8 DEntry_CopyCounter(u8 index) const;
|
||||
// get first block for file
|
||||
u16 DEntry_FirstBlock(u8 index);
|
||||
u16 DEntry_FirstBlock(u8 index) const;
|
||||
// get file length in blocks
|
||||
u16 DEntry_BlockCount(u8 index);
|
||||
u32 DEntry_CommentsAddress(u8 index);
|
||||
// buffer needs to be a char[32] or bigger
|
||||
bool DEntry_Comment1(u8 index, char *buffer);
|
||||
// buffer needs to be a char[32] or bigger
|
||||
bool DEntry_Comment2(u8 index, char *buffer);
|
||||
u16 DEntry_BlockCount(u8 index) const;
|
||||
u32 DEntry_CommentsAddress(u8 index) const;
|
||||
std::string GetSaveComment1(u8 index) const;
|
||||
std::string GetSaveComment2(u8 index) const;
|
||||
// Copies a DEntry from u8 index to DEntry& data
|
||||
bool DEntry_Copy(u8 index, DEntry& data);
|
||||
bool GetDEntry(u8 index, DEntry &dest) const;
|
||||
|
||||
// assumes there's enough space in buffer
|
||||
// old determines if function uses old or new method of copying data
|
||||
// some functions only work with old way, some only work with new way
|
||||
// TODO: find a function that works for all calls or split into 2 functions
|
||||
u32 DEntry_GetSaveData(u8 index, u8* buffer, bool old);
|
||||
u32 GetSaveData(u8 index, std::vector<GCMBlock> &saveBlocks) const;
|
||||
|
||||
// adds the file to the directory and copies its contents
|
||||
// if remove > 0 it will pad bat.map with 0's sizeof remove
|
||||
u32 ImportFile(DEntry& direntry, u8* contents, int remove);
|
||||
u32 ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks);
|
||||
|
||||
// delete a file from the directory
|
||||
u32 RemoveFile(u8 index);
|
||||
|
||||
// reads a save from another memcard, and imports the data into this memcard
|
||||
u32 CopyFrom(GCMemcard& source, u8 index);
|
||||
u32 CopyFrom(const GCMemcard& source, u8 index);
|
||||
|
||||
// reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file
|
||||
u32 ImportGci(const char* inputFile, std::string outputFile);
|
||||
u32 ImportGci(const char* inputFile,const std::string &outputFile);
|
||||
|
||||
// writes a .gci file to disk containing index
|
||||
u32 ExportGci(u8 index, const char* fileName, std::string* fileName2);
|
||||
u32 ExportGci(u8 index, const char* fileName, const std::string &directory) const;
|
||||
|
||||
// GCI files are untouched, SAV files are byteswapped
|
||||
// GCS files have the block count set, default is 1 (For export as GCS)
|
||||
void Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length = BLOCK_SIZE);
|
||||
static void Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length = BLOCK_SIZE);
|
||||
|
||||
// reads the banner image
|
||||
bool ReadBannerRGBA8(u8 index, u32* buffer);
|
||||
bool ReadBannerRGBA8(u8 index, u32* buffer) const;
|
||||
|
||||
// reads the animation frames
|
||||
u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays);
|
||||
u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#include "ChunkFile.h"
|
||||
#include "ProcessorInterface.h"
|
||||
#include "Memmap.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
#include "../PowerPC/JitCommon/JitBase.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
#include "GPFifo.h"
|
||||
|
||||
@@ -96,6 +96,15 @@ 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 && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end()))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -427,6 +427,7 @@ void Wiimote::ReadData(const wm_read_data* const rd)
|
||||
if (address + size > WIIMOTE_EEPROM_SIZE)
|
||||
{
|
||||
PanicAlert("ReadData: address + size out of bounds");
|
||||
delete [] block;
|
||||
return;
|
||||
}
|
||||
// generate a read error
|
||||
|
||||
@@ -127,11 +127,6 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
|
||||
bti = [[IOBluetoothDeviceInquiry alloc] init];
|
||||
[bti setDelegate: sbt];
|
||||
[bti setInquiryLength: 5];
|
||||
[bti setSearchCriteria: kBluetoothServiceClassMajorAny
|
||||
majorDeviceClass: kBluetoothDeviceClassMajorPeripheral
|
||||
minorDeviceClass: kBluetoothDeviceClassMinorAny
|
||||
];
|
||||
[bti setUpdateNewDeviceNames: NO];
|
||||
|
||||
if ([bti start] == kIOReturnSuccess)
|
||||
[bti retain];
|
||||
@@ -149,6 +144,9 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
|
||||
en = [[bti foundDevices] objectEnumerator];
|
||||
for (int i = 0; i < found_devices; i++)
|
||||
{
|
||||
IOBluetoothDevice *dev = [en nextObject];
|
||||
if (!IsValidBluetoothName([[dev name] UTF8String]))
|
||||
continue;
|
||||
// Find an unused slot
|
||||
for (int k = 0; k < MAX_WIIMOTES; k++) {
|
||||
if (wm[k] != NULL ||
|
||||
@@ -156,7 +154,7 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
|
||||
continue;
|
||||
|
||||
wm[k] = new Wiimote(k);
|
||||
wm[k]->btd = [en nextObject];
|
||||
wm[k]->btd = dev;
|
||||
found_wiimotes++;
|
||||
break;
|
||||
}
|
||||
@@ -177,10 +175,6 @@ bool Wiimote::Connect()
|
||||
if (IsConnected())
|
||||
return false;
|
||||
|
||||
if ([btd remoteNameRequest:nil] == kIOReturnSuccess)
|
||||
m_motion_plus_inside =
|
||||
static_cast<bool>([[btd getName] hasSuffix:@"-TR"]);
|
||||
|
||||
[btd openL2CAPChannelSync: &cchan
|
||||
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
|
||||
[btd openL2CAPChannelSync: &ichan
|
||||
|
||||
@@ -50,7 +50,6 @@ Wiimote::Wiimote(const unsigned int _index)
|
||||
#endif
|
||||
, leds(0), m_last_data_report(Report((u8 *)NULL, 0))
|
||||
, m_channel(0), m_connected(false)
|
||||
, m_motion_plus_inside(false)
|
||||
{
|
||||
#if defined(__linux__) && HAVE_BLUEZ
|
||||
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
|
||||
@@ -143,16 +142,16 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
|
||||
rpt.second = (u8)size;
|
||||
memcpy(rpt.first, (u8*)data, size);
|
||||
|
||||
// Convert output DATA packets to SET_REPORT packets for non-TR
|
||||
// Wiimotes. Nintendo Wiimotes work without this translation, but 3rd
|
||||
// Convert output DATA packets to SET_REPORT packets.
|
||||
// Nintendo Wiimotes work without this translation, but 3rd
|
||||
// party ones don't.
|
||||
u8 head = m_motion_plus_inside ? 0xa2 : 0x52;
|
||||
if (rpt.first[0] == 0xa2)
|
||||
{
|
||||
rpt.first[0] = head;
|
||||
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
||||
}
|
||||
|
||||
if (rpt.first[0] == head && rpt.first[1] == 0x18 && rpt.second == 23)
|
||||
if (rpt.first[0] == (WM_SET_REPORT | WM_BT_OUTPUT) &&
|
||||
rpt.first[1] == 0x18 && rpt.second == 23)
|
||||
{
|
||||
m_audio_reports.Push(rpt);
|
||||
return;
|
||||
@@ -513,4 +512,19 @@ void StateChange(EMUSTATE_CHANGE newState)
|
||||
// TODO: disable/enable auto reporting, maybe
|
||||
}
|
||||
|
||||
#define ARRAYSIZE(_arr) (sizeof(_arr)/(sizeof(_arr[0])))
|
||||
|
||||
bool IsValidBluetoothName(const char* name) {
|
||||
static const char* kValidWiiRemoteBluetoothNames[] = {
|
||||
"Nintendo RVL-CNT-01",
|
||||
"Nintendo RVL-CNT-01-TR",
|
||||
"Nintendo RVL-WBC-01",
|
||||
};
|
||||
for (size_t i = 0; i < ARRAYSIZE(kValidWiiRemoteBluetoothNames); i++)
|
||||
if (strcmp(name, kValidWiiRemoteBluetoothNames[i]) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}; // end of namespace
|
||||
|
||||
@@ -95,7 +95,6 @@ private:
|
||||
void ThreadFunc();
|
||||
|
||||
bool m_connected;
|
||||
bool m_motion_plus_inside;
|
||||
std::thread m_wiimote_thread;
|
||||
Common::FifoQueue<Report> m_read_reports;
|
||||
Common::FifoQueue<Report> m_write_reports;
|
||||
@@ -114,6 +113,8 @@ void StateChange(EMUSTATE_CHANGE newState);
|
||||
|
||||
int FindWiimotes(Wiimote** wm, int max_wiimotes);
|
||||
|
||||
bool IsValidBluetoothName(const char* name);
|
||||
|
||||
}; // WiimoteReal
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,14 @@
|
||||
#define WM_OUTPUT_CHANNEL 0x11
|
||||
#define WM_INPUT_CHANNEL 0x13
|
||||
|
||||
// The 4 most significant bits of the first byte of an outgoing command must be
|
||||
// 0x50 if sending on the command channel and 0xA0 if sending on the interrupt
|
||||
// channel. On Mac we use interrupt channel; on Windows/Linux, command.
|
||||
#ifndef __APPLE__
|
||||
#define WM_SET_REPORT 0x50
|
||||
#else
|
||||
#define WM_SET_REPORT 0xA0
|
||||
#endif
|
||||
|
||||
// Commands
|
||||
#define WM_CMD_RUMBLE 0x10
|
||||
|
||||
@@ -69,8 +69,13 @@ TDeviceMap g_DeviceMap;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
typedef std::map<u32, std::string> TFileNameMap;
|
||||
TFileNameMap g_FileNameMap;
|
||||
u32 g_LastDeviceID;
|
||||
|
||||
#define IPC_MAX_FDS 0x18
|
||||
#define ES_MAX_COUNT 2
|
||||
IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
|
||||
bool es_inuse[ES_MAX_COUNT];
|
||||
IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
|
||||
|
||||
|
||||
typedef std::deque<u32> ipc_msg_queue;
|
||||
static ipc_msg_queue request_queue; // ppc -> arm
|
||||
@@ -79,14 +84,28 @@ static ipc_msg_queue reply_queue; // arm -> ppc
|
||||
void Init()
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
|
||||
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
g_FdMap[i] = NULL;
|
||||
}
|
||||
|
||||
u32 i = IPC_FIRST_HARDWARE_ID;
|
||||
i = 0;
|
||||
// Build hardware devices
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
|
||||
|
||||
// IOS allows two ES devices at a time<
|
||||
u32 j;
|
||||
for (j=0; j<ES_MAX_COUNT; j++)
|
||||
{
|
||||
g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
|
||||
es_inuse[j] = false;
|
||||
}
|
||||
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++;
|
||||
@@ -99,13 +118,24 @@ void Init()
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++;
|
||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++;
|
||||
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_"));
|
||||
|
||||
g_LastDeviceID = IPC_FIRST_FILEIO_ID;
|
||||
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++;
|
||||
}
|
||||
|
||||
void Reset(bool _bHard)
|
||||
{
|
||||
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware())
|
||||
{
|
||||
// close all files and delete their resources
|
||||
g_FdMap[i]->Close(0, true);
|
||||
delete g_FdMap[i];
|
||||
}
|
||||
g_FdMap[i] = NULL;
|
||||
}
|
||||
|
||||
TDeviceMap::iterator itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
@@ -114,21 +144,17 @@ void Reset(bool _bHard)
|
||||
// Force close
|
||||
itr->second->Close(0, true);
|
||||
// Hardware should not be deleted unless it is a hard reset
|
||||
if (_bHard || !itr->second->IsHardware())
|
||||
if (_bHard)
|
||||
delete itr->second;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
// Skip hardware devices if not a hard reset
|
||||
itr = (_bHard) ? g_DeviceMap.begin() : g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID);
|
||||
// Erase devices
|
||||
g_DeviceMap.erase(itr, g_DeviceMap.end());
|
||||
g_FileNameMap.clear();
|
||||
|
||||
if (_bHard)
|
||||
{
|
||||
g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
|
||||
}
|
||||
request_queue.clear();
|
||||
reply_queue.clear();
|
||||
|
||||
g_LastDeviceID = IPC_FIRST_FILEIO_ID;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@@ -138,41 +164,53 @@ void Shutdown()
|
||||
|
||||
void SetDefaultContentFile(const std::string& _rFilename)
|
||||
{
|
||||
CWII_IPC_HLE_Device_es* pDevice =
|
||||
(CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
|
||||
if (pDevice)
|
||||
pDevice->LoadWAD(_rFilename);
|
||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0)
|
||||
{
|
||||
((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void ES_DIVerify(u8 *_pTMD, u32 _sz)
|
||||
{
|
||||
CWII_IPC_HLE_Device_es* pDevice =
|
||||
(CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
|
||||
if (pDevice)
|
||||
pDevice->ES_DIVerify(_pTMD, _sz);
|
||||
else
|
||||
ERROR_LOG(WII_IPC_ES, "DIVerify called but /dev/es is not available");
|
||||
CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
|
||||
}
|
||||
|
||||
void SDIO_EventNotify()
|
||||
{
|
||||
CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
|
||||
(CWII_IPC_HLE_Device_sdio_slot0*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/sdio/slot0")));
|
||||
(CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0"));
|
||||
if (pDevice)
|
||||
pDevice->EventNotify();
|
||||
}
|
||||
int getFreeDeviceId()
|
||||
{
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
if (g_FdMap[i] == NULL)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GetDeviceIDByName(const std::string& _rDeviceName)
|
||||
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
|
||||
{
|
||||
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
|
||||
while(itr != g_DeviceMap.end())
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second->GetDeviceName() == _rDeviceName)
|
||||
return itr->first;
|
||||
if (itr->second && itr->second->GetDeviceName() == _rDeviceName)
|
||||
return itr->second;
|
||||
++itr;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
||||
@@ -180,17 +218,7 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
||||
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
||||
return g_DeviceMap[_ID];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DeleteDeviceByID(u32 ID)
|
||||
{
|
||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID);
|
||||
if (pDevice)
|
||||
delete pDevice;
|
||||
|
||||
g_DeviceMap.erase(ID);
|
||||
g_FileNameMap.erase(ID);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
|
||||
@@ -208,60 +236,86 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(g_LastDeviceID);
|
||||
p.Do(request_queue);
|
||||
p.Do(reply_queue);
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
TFileNameMap::const_iterator itr;
|
||||
// Delete file Handles
|
||||
itr = g_FileNameMap.begin();
|
||||
while (itr != g_FileNameMap.end())
|
||||
{
|
||||
TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first);
|
||||
if (devitr != g_DeviceMap.end())
|
||||
TDeviceMap::const_iterator itr;
|
||||
|
||||
itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second->IsHardware())
|
||||
{
|
||||
if (devitr->second)
|
||||
delete devitr->second;
|
||||
g_DeviceMap.erase(itr->first);
|
||||
itr->second->DoState(p);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
// Load file names
|
||||
p.Do(g_FileNameMap);
|
||||
// Rebuild file handles
|
||||
itr = g_FileNameMap.begin();
|
||||
while (itr != g_FileNameMap.end())
|
||||
}
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
g_DeviceMap[itr->first] = new CWII_IPC_HLE_Device_FileIO(itr->first, itr->second);
|
||||
++itr;
|
||||
u32 exists;
|
||||
p.Do(exists);
|
||||
if (exists)
|
||||
{
|
||||
u32 isHw;
|
||||
p.Do(isHw);
|
||||
if (isHw)
|
||||
{
|
||||
u32 hwId;
|
||||
p.Do(hwId);
|
||||
g_FdMap[i] = AccessDeviceByID(hwId);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
|
||||
g_FdMap[i]->DoState(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_FdMap[i] = NULL;
|
||||
}
|
||||
}
|
||||
for (i=0; i<ES_MAX_COUNT; i++)
|
||||
{
|
||||
p.Do(es_inuse[i]);
|
||||
u32 handleID = es_handles[i]->GetDeviceID();
|
||||
p.Do(handleID);
|
||||
|
||||
es_handles[i] = AccessDeviceByID(handleID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Do(g_FileNameMap);
|
||||
}
|
||||
|
||||
p.Do(request_queue);
|
||||
p.Do(reply_queue);
|
||||
|
||||
|
||||
TDeviceMap::const_iterator itr;
|
||||
//first, all the real devices
|
||||
//(because we need fs to be deserialized first)
|
||||
itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (itr->second->IsHardware())
|
||||
itr->second->DoState(p);
|
||||
++itr;
|
||||
}
|
||||
//then all the files
|
||||
itr = g_DeviceMap.begin();
|
||||
while (itr != g_DeviceMap.end())
|
||||
{
|
||||
if (!itr->second->IsHardware())
|
||||
itr->second->DoState(p);
|
||||
++itr;
|
||||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
u32 exists = g_FdMap[i] ? 1 : 0;
|
||||
p.Do(exists);
|
||||
if (exists)
|
||||
{
|
||||
u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0;
|
||||
p.Do(isHw);
|
||||
if (isHw)
|
||||
{
|
||||
u32 hwId = g_FdMap[i]->GetDeviceID();
|
||||
p.Do(hwId);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_FdMap[i]->DoState(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<ES_MAX_COUNT; i++)
|
||||
{
|
||||
p.Do(es_inuse[i]);
|
||||
u32 handleID = es_handles[i]->GetDeviceID();
|
||||
p.Do(handleID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,67 +324,110 @@ void ExecuteCommand(u32 _Address)
|
||||
bool CmdSuccess = false;
|
||||
|
||||
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
|
||||
int DeviceID = Memory::Read_U32(_Address + 8);
|
||||
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
|
||||
volatile int DeviceID = Memory::Read_U32(_Address + 8);
|
||||
|
||||
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) ", _Address, Command, DeviceID);
|
||||
IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL;
|
||||
|
||||
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case COMMAND_OPEN_DEVICE:
|
||||
{
|
||||
// Create a new HLE device. The Mode and DeviceName is given to us but we
|
||||
// generate a DeviceID to be used for access to this device until it is Closed.
|
||||
std::string DeviceName;
|
||||
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
||||
{
|
||||
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
||||
DeviceID = getFreeDeviceId();
|
||||
|
||||
std::string DeviceName;
|
||||
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
||||
|
||||
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
||||
DeviceID = GetDeviceIDByName(DeviceName);
|
||||
|
||||
// check if a device with this name has been created already
|
||||
if (DeviceName.find("/dev/") == std::string::npos || DeviceID == -1)
|
||||
{
|
||||
if (DeviceName.find("/dev/") == 0)
|
||||
|
||||
WARN_LOG(WII_IPC_HLE, "Tried to open %s as %d", DeviceName.c_str(), DeviceID);
|
||||
if (DeviceID >= 0)
|
||||
{
|
||||
if (DeviceName.find("/dev/es") == 0)
|
||||
{
|
||||
u32 j;
|
||||
for (j=0; j<ES_MAX_COUNT; j++)
|
||||
{
|
||||
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
|
||||
if (!es_inuse[j])
|
||||
{
|
||||
es_inuse[j] = true;
|
||||
g_FdMap[DeviceID] = es_handles[j];
|
||||
CmdSuccess = es_handles[j]->Open(_Address, Mode);
|
||||
Memory::Write_U32(DeviceID, _Address+4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == ES_MAX_COUNT)
|
||||
{
|
||||
Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
|
||||
pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("_Unimplemented_Device_")));
|
||||
}
|
||||
else if (DeviceName.find("/dev/") == 0)
|
||||
{
|
||||
pDevice = GetDeviceByName(DeviceName);
|
||||
if (pDevice)
|
||||
{
|
||||
g_FdMap[DeviceID] = pDevice;
|
||||
CmdSuccess = pDevice->Open(_Address, Mode);
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
Memory::Write_U32(DeviceID, _Address+4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new file handle
|
||||
u32 CurrentDeviceID = g_LastDeviceID;
|
||||
pDevice = CreateFileIO(CurrentDeviceID, DeviceName);
|
||||
g_DeviceMap[CurrentDeviceID] = pDevice;
|
||||
g_FileNameMap[CurrentDeviceID] = DeviceName;
|
||||
g_LastDeviceID++;
|
||||
|
||||
CmdSuccess = pDevice->Open(_Address, Mode);
|
||||
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode);
|
||||
WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
|
||||
Memory::Write_U32(FS_ENOENT, _Address+4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// F|RES: prolly the re-open is just a mode change
|
||||
pDevice = AccessDeviceByID(DeviceID);
|
||||
}
|
||||
else
|
||||
{
|
||||
IWII_IPC_HLE_Device* pDevice = CreateFileIO(DeviceID, DeviceName);
|
||||
CmdSuccess = pDevice->Open(_Address, Mode);
|
||||
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
if (Memory::Read_U32(_Address + 4) == DeviceID)
|
||||
{
|
||||
g_FdMap[DeviceID] = pDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pDevice;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_CLOSE_DEVICE:
|
||||
if (pDevice)
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Close(_Address);
|
||||
|
||||
u32 j;
|
||||
for (j=0; j<ES_MAX_COUNT; j++)
|
||||
{
|
||||
if (es_handles[j] == g_FdMap[DeviceID])
|
||||
{
|
||||
es_inuse[j] = false;
|
||||
}
|
||||
}
|
||||
|
||||
g_FdMap[DeviceID] = NULL;
|
||||
|
||||
// Don't delete hardware
|
||||
if (!pDevice->IsHardware())
|
||||
DeleteDeviceByID(DeviceID);
|
||||
delete pDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -338,50 +435,67 @@ void ExecuteCommand(u32 _Address)
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_READ:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Read(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EINVAL, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_WRITE:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Write(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EINVAL, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_SEEK:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->Seek(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory::Write_U32(FS_EINVAL, _Address + 4);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_IOCTL:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->IOCtl(_Address);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case COMMAND_IOCTLV:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
CmdSuccess = pDevice->IOCtlV(_Address);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// It seems that the original hardware overwrites the command after it has been
|
||||
@@ -453,9 +567,10 @@ void Update()
|
||||
void UpdateDevices()
|
||||
{
|
||||
// Check if a hardware device must be updated
|
||||
TDeviceMap::const_iterator itrEnd = g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID);
|
||||
for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != itrEnd; ++itr) {
|
||||
if (itr->second->IsOpened() && itr->second->Update()) {
|
||||
for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr)
|
||||
{
|
||||
if (itr->second->IsOpened() && itr->second->Update())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ class IWII_IPC_HLE_Device;
|
||||
namespace WII_IPC_HLE_Interface
|
||||
{
|
||||
|
||||
#define IPC_FIRST_HARDWARE_ID 0 // first IPC device ID
|
||||
#define IPC_FIRST_FILEIO_ID 33 // first IPC file ID
|
||||
|
||||
#define IPC_FIRST_ID 0x00 // first IPC device ID
|
||||
#define IPC_MAX_FILES 0x10 // first IPC file ID
|
||||
|
||||
// Init
|
||||
void Init();
|
||||
|
||||
@@ -46,14 +46,13 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz);
|
||||
|
||||
void SDIO_EventNotify();
|
||||
|
||||
int GetDeviceIDByName(const std::string& _rDeviceName);
|
||||
|
||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
|
||||
|
||||
void DeleteDeviceByID(u32 _ID);
|
||||
|
||||
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName);
|
||||
|
||||
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName);
|
||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
|
||||
int getFreeDeviceId();
|
||||
|
||||
// Update
|
||||
void Update();
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class PointerWrap;
|
||||
#define FS_ENOENT2 (u32)-106 // File not found
|
||||
#define FS_ENFILE (u32)-107 // Too many fds open
|
||||
#define FS_EFBIG (u32)-108 // max block count reached?
|
||||
#define FS_ENFILE2 (u32)-109 // Too many fds open
|
||||
#define FS_EFDEXHAUSTED (u32)-109 // Too many fds open
|
||||
#define FS_ENAMELEN (u32)-110 // pathname is too long
|
||||
#define FS_EFDOPEN (u32)-111 // FD is already open
|
||||
#define FS_EIO2 (u32)-114 // returned on ECC error
|
||||
@@ -47,6 +47,7 @@ class PointerWrap;
|
||||
#define FS_EDIRDEPTH (u32)-116 // max directory depth exceeded
|
||||
#define FS_EBUSY2 (u32)-118 // Resource busy
|
||||
//#define FS_EFATAL (u32)-119 // fatal error not used by IOS as fatal ERROR
|
||||
#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time
|
||||
|
||||
class IWII_IPC_HLE_Device
|
||||
{
|
||||
|
||||
@@ -428,6 +428,16 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
||||
break;
|
||||
|
||||
case DVDLowAudioBufferConfig:
|
||||
/*
|
||||
For more information: http://www.crazynation.org/GC/GC_DD_TECH/GCTech.htm
|
||||
|
||||
Upon Power up or reset , 2 commands must be issued for proper use of audio streaming:
|
||||
DVDReadDiskID A8000040,00000000,00000020
|
||||
DVDLowAudioBufferConfig E4xx00yy,00000000,00000020
|
||||
|
||||
xx=byte 8 [0 or 1] from the disk header retrieved from DVDReadDiskID
|
||||
yy=0 (if xx=0) or 0xA (if xx=1)
|
||||
*/
|
||||
ERROR_LOG(WII_IPC_DVD, "DVDLowAudioBufferConfig");
|
||||
break;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
static Common::replace_v replacements;
|
||||
|
||||
// This is used by several of the FileIO and /dev/fs/ functions
|
||||
// This is used by several of the FileIO and /dev/fs functions
|
||||
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size)
|
||||
{
|
||||
std::string path_full = File::GetUserPath(D_WIIROOT_IDX);
|
||||
@@ -128,7 +128,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
|
||||
|
||||
// The file must exist before we can open it
|
||||
// It should be created by ISFS_CreateFile, not here
|
||||
if(File::Exists(m_Filename))
|
||||
if (File::Exists(m_Filename))
|
||||
{
|
||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode);
|
||||
ReturnValue = m_DeviceID;
|
||||
@@ -146,28 +146,31 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CWII_IPC_HLE_Device_FileIO::OpenFile()
|
||||
{
|
||||
switch(m_Mode)
|
||||
switch (m_Mode)
|
||||
{
|
||||
case ISFS_OPEN_READ:
|
||||
{
|
||||
m_pFileHandle.Open(m_Filename, "rb");
|
||||
break;
|
||||
|
||||
// "r+b" is technically wrong, but OPEN_WRITE should not truncate the file as "wb" does.
|
||||
}
|
||||
case ISFS_OPEN_WRITE:
|
||||
{
|
||||
m_pFileHandle.Open(m_Filename, "r+b");
|
||||
break;
|
||||
|
||||
}
|
||||
case ISFS_OPEN_RW:
|
||||
{
|
||||
m_pFileHandle.Open(m_Filename, "r+b");
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
{
|
||||
PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m_pFileHandle.IsOpen();
|
||||
}
|
||||
|
||||
@@ -178,21 +181,21 @@ void CWII_IPC_HLE_Device_FileIO::CloseFile()
|
||||
|
||||
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
{
|
||||
u32 ReturnValue = FS_RESULT_FATAL;
|
||||
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
u32 ReturnValue = FS_RESULT_FATAL;
|
||||
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
ReturnValue = FS_RESULT_FATAL;
|
||||
|
||||
const u64 fileSize = m_pFileHandle.GetSize();
|
||||
const u64 fileSize = m_pFileHandle.GetSize();
|
||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize);
|
||||
switch(Mode){
|
||||
switch (Mode){
|
||||
case 0:
|
||||
{
|
||||
if(SeekPosition >=0 && SeekPosition <= fileSize)
|
||||
if (SeekPosition >=0 && SeekPosition <= fileSize)
|
||||
{
|
||||
m_SeekPos = SeekPosition;
|
||||
ReturnValue = m_SeekPos;
|
||||
@@ -202,7 +205,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
case 1:
|
||||
{
|
||||
s32 wantedPos = SeekPosition+m_SeekPos;
|
||||
if(wantedPos >=0 && wantedPos <= fileSize)
|
||||
if (wantedPos >=0 && wantedPos <= fileSize)
|
||||
{
|
||||
m_SeekPos = wantedPos;
|
||||
ReturnValue = m_SeekPos;
|
||||
@@ -212,7 +215,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
case 2:
|
||||
{
|
||||
s32 wantedPos = fileSize+m_SeekPos;
|
||||
if(wantedPos >=0 && wantedPos <= fileSize)
|
||||
if (wantedPos >=0 && wantedPos <= fileSize)
|
||||
{
|
||||
m_SeekPos = wantedPos;
|
||||
ReturnValue = m_SeekPos;
|
||||
@@ -244,7 +247,7 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
||||
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
if (m_Mode == ISFS_OPEN_WRITE)
|
||||
{
|
||||
@@ -284,7 +287,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
||||
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
if (m_Mode == ISFS_OPEN_READ)
|
||||
{
|
||||
@@ -318,21 +321,14 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
DumpCommands(_CommandAddress);
|
||||
#endif
|
||||
const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
u32 ReturnValue = 0;
|
||||
|
||||
//u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
//u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||
//u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||
//u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||
|
||||
// Return Value
|
||||
u32 ReturnValue = 0; // no error
|
||||
|
||||
switch(Parameter)
|
||||
switch (Parameter)
|
||||
{
|
||||
case ISFS_IOCTL_GETFILESTATS:
|
||||
{
|
||||
if(OpenFile())
|
||||
if (OpenFile())
|
||||
{
|
||||
u32 m_FileLength = (u32)m_pFileHandle.GetSize();
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/objects.h>
|
||||
|
||||
std::string CWII_IPC_HLE_Device_es::m_ContentFile;
|
||||
|
||||
CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName)
|
||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||
, m_pContentLoader(NULL)
|
||||
@@ -276,8 +278,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
||||
|
||||
m_ContentAccessMap[CFD].m_Position = 0;
|
||||
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
|
||||
_dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
|
||||
|
||||
|
||||
if (m_ContentAccessMap[CFD].m_pContent == NULL)
|
||||
CFD = 0xffffffff; //TODO: what is the correct error value here?
|
||||
|
||||
@@ -775,21 +776,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
||||
PC = DolLoader.GetEntryPoint() | 0x80000000;
|
||||
IOSv = ContentLoader.GetIosVersion();
|
||||
bSuccess = true;
|
||||
// Reset the connection of all connected wiimotes
|
||||
// ugly haxx
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
if (s_Usb->m_WiiMotes[i].IsConnected())
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
s_Usb->m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -802,8 +789,32 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
||||
IOSv = TitleID & 0xffff;
|
||||
}
|
||||
if (!bSuccess)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string tContentFile(m_ContentFile.c_str());
|
||||
WII_IPC_HLE_Interface::Reset(true);
|
||||
WII_IPC_HLE_Interface::Init();
|
||||
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
|
||||
{
|
||||
if (s_Usb->m_WiiMotes[i].IsConnected())
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
s_Usb->m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
|
||||
WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile);
|
||||
}
|
||||
// Pass the "#002 check"
|
||||
// Apploader should write the IOS version and revision to 0x3140, and compare it
|
||||
// to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev...
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
virtual bool Close(u32 _CommandAddress, bool _bForce);
|
||||
|
||||
virtual bool IOCtlV(u32 _CommandAddress);
|
||||
u32 ES_DIVerify(u8 *_pTMD, u32 _sz);
|
||||
static u32 ES_DIVerify(u8 *_pTMD, u32 _sz);
|
||||
private:
|
||||
|
||||
enum
|
||||
@@ -135,7 +135,7 @@ private:
|
||||
u64 m_TitleID;
|
||||
u32 AccessIdentID;
|
||||
// This should only be cleared on power reset
|
||||
std::string m_ContentFile;
|
||||
static std::string m_ContentFile;
|
||||
|
||||
static u8 *keyTable[11];
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ bool BeginRecordingInput(int controllers)
|
||||
g_rerecords = 0;
|
||||
g_playMode = MODE_RECORDING;
|
||||
|
||||
delete tmpInput;
|
||||
delete [] tmpInput;
|
||||
tmpInput = new u8[MAX_DTM_LENGTH];
|
||||
g_currentByte = g_totalBytes = 0;
|
||||
|
||||
@@ -627,6 +627,10 @@ void LoadInput(const char *filename)
|
||||
|
||||
if (!g_bReadOnly)
|
||||
{
|
||||
if (g_rerecords > tmpHeader.numRerecords)
|
||||
{
|
||||
tmpHeader.numRerecords = g_rerecords;
|
||||
}
|
||||
tmpHeader.numRerecords++;
|
||||
t_record.Seek(0, SEEK_SET);
|
||||
t_record.WriteArray(&tmpHeader, 1);
|
||||
@@ -653,7 +657,7 @@ void LoadInput(const char *filename)
|
||||
g_totalInputCount = tmpHeader.inputCount;
|
||||
|
||||
g_totalBytes = totalSavedBytes;
|
||||
delete tmpInput;
|
||||
delete [] tmpInput;
|
||||
tmpInput = new u8[MAX_DTM_LENGTH];
|
||||
t_record.ReadArray(tmpInput, (size_t)g_totalBytes);
|
||||
}
|
||||
@@ -707,7 +711,7 @@ void LoadInput(const char *filename)
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete movInput;
|
||||
delete [] movInput;
|
||||
}
|
||||
}
|
||||
t_record.Close();
|
||||
|
||||
@@ -181,7 +181,7 @@ union UGeckoInstruction
|
||||
u32 : 11;
|
||||
u32 CRBB : 5;
|
||||
u32 CRBA : 5;
|
||||
u32 CRBD : 5;
|
||||
u32 CRBD : 5;
|
||||
u32 : 6;
|
||||
};
|
||||
|
||||
@@ -235,9 +235,9 @@ union UGeckoInstruction
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 : 17;
|
||||
u32 FM : 8;
|
||||
u32 : 7;
|
||||
u32 : 17;
|
||||
u32 FM : 8;
|
||||
u32 : 7;
|
||||
};
|
||||
|
||||
// paired
|
||||
@@ -247,8 +247,8 @@ union UGeckoInstruction
|
||||
u32 Ix : 3;
|
||||
u32 Wx : 1;
|
||||
u32 : 1;
|
||||
u32 I : 3;
|
||||
u32 W : 1;
|
||||
u32 I : 3;
|
||||
u32 W : 1;
|
||||
u32 : 16;
|
||||
};
|
||||
|
||||
@@ -319,7 +319,7 @@ union UReg_XER
|
||||
u32 Hex;
|
||||
|
||||
UReg_XER(u32 _hex) { Hex = _hex; }
|
||||
UReg_XER() { Hex = 0; }
|
||||
UReg_XER() { Hex = 0; }
|
||||
};
|
||||
|
||||
// Machine State Register
|
||||
@@ -351,7 +351,7 @@ union UReg_MSR
|
||||
u32 Hex;
|
||||
|
||||
UReg_MSR(u32 _hex) { Hex = _hex; }
|
||||
UReg_MSR() { Hex = 0; }
|
||||
UReg_MSR() { Hex = 0; }
|
||||
};
|
||||
|
||||
// Floating Point Status and Control Register
|
||||
@@ -487,13 +487,47 @@ union UReg_SPR1
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
u32 htaborg : 16;
|
||||
u32 : 7;
|
||||
u32 htabmask : 9;
|
||||
u32 htaborg : 16;
|
||||
u32 : 7;
|
||||
u32 htabmask : 9;
|
||||
};
|
||||
};
|
||||
|
||||
// MMCR0 - Monitor Mode Control Register 0 format
|
||||
union UReg_MMCR0
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
u32 PMC2SELECT : 6;
|
||||
u32 PMC1SELECT : 7;
|
||||
u32 PMCTRIGGER : 1;
|
||||
u32 PMCINTCONTROL : 1;
|
||||
u32 PMC1INTCONTROL : 1;
|
||||
u32 THRESHOLD : 6;
|
||||
u32 INTONBITTRANS : 1;
|
||||
u32 RTCSELECT : 2;
|
||||
u32 DISCOUNT : 1;
|
||||
u32 ENINT : 1;
|
||||
u32 DMR : 1;
|
||||
u32 DMS : 1;
|
||||
u32 DU : 1;
|
||||
u32 DP : 1;
|
||||
u32 DIS : 1;
|
||||
};
|
||||
};
|
||||
|
||||
// MMCR1 - Monitor Mode Control Register 1 format
|
||||
union UReg_MMCR1
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
u32 : 22;
|
||||
u32 PMC4SELECT : 5;
|
||||
u32 PMC3SELECT : 5;
|
||||
};
|
||||
};
|
||||
|
||||
// Write Pipe Address Register
|
||||
union UReg_WPAR
|
||||
@@ -516,7 +550,7 @@ union UReg_DMAU
|
||||
struct
|
||||
{
|
||||
u32 DMA_LEN_U : 5;
|
||||
u32 MEM_ADDR : 27;
|
||||
u32 MEM_ADDR : 27;
|
||||
};
|
||||
u32 Hex;
|
||||
|
||||
@@ -533,7 +567,7 @@ union UReg_DMAL
|
||||
u32 DMA_T : 1;
|
||||
u32 DMA_LEN_L : 2;
|
||||
u32 DMA_LD : 1;
|
||||
u32 LC_ADDR : 27;
|
||||
u32 LC_ADDR : 27;
|
||||
};
|
||||
u32 Hex;
|
||||
|
||||
@@ -545,11 +579,11 @@ union UReg_BAT_Up
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 VP : 1;
|
||||
u32 VS : 1;
|
||||
u32 VP : 1;
|
||||
u32 VS : 1;
|
||||
u32 BL : 11; // Block length (aka block size mask)
|
||||
u32 : 4;
|
||||
u32 BEPI : 15;
|
||||
u32 BEPI : 15;
|
||||
};
|
||||
u32 Hex;
|
||||
|
||||
@@ -561,8 +595,8 @@ union UReg_BAT_Lo
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 PP : 2;
|
||||
u32 : 1;
|
||||
u32 PP : 2;
|
||||
u32 : 1;
|
||||
u32 WIMG : 4;
|
||||
u32 : 10;
|
||||
u32 BRPN : 15; // Physical Block Number
|
||||
@@ -586,7 +620,7 @@ union UReg_PTE
|
||||
u64 WIMG : 4;
|
||||
u64 C : 1;
|
||||
u64 R : 1;
|
||||
u64 : 3;
|
||||
u64 : 3;
|
||||
u64 RPN : 20;
|
||||
|
||||
};
|
||||
@@ -623,16 +657,16 @@ enum
|
||||
// Special purpose register indices
|
||||
enum
|
||||
{
|
||||
SPR_XER = 1,
|
||||
SPR_XER = 1,
|
||||
SPR_LR = 8,
|
||||
SPR_CTR = 9,
|
||||
SPR_DSISR = 18,
|
||||
SPR_DAR = 19,
|
||||
SPR_DAR = 19,
|
||||
SPR_DEC = 22,
|
||||
SPR_SDR = 25,
|
||||
SPR_SDR = 25,
|
||||
SPR_SRR0 = 26,
|
||||
SPR_SRR1 = 27,
|
||||
SPR_TL = 268,
|
||||
SPR_TL = 268,
|
||||
SPR_TU = 269,
|
||||
SPR_TL_W = 284,
|
||||
SPR_TU_W = 285,
|
||||
@@ -669,7 +703,17 @@ enum
|
||||
SPR_ECID_U = 924,
|
||||
SPR_ECID_M = 925,
|
||||
SPR_ECID_L = 926,
|
||||
SPR_L2CR = 1017
|
||||
SPR_L2CR = 1017,
|
||||
|
||||
SPR_UMMCR0 = 936,
|
||||
SPR_MMCR0 = 952,
|
||||
SPR_PMC1 = 953,
|
||||
SPR_PMC2 = 954,
|
||||
|
||||
SPR_UMMCR1 = 940,
|
||||
SPR_MMCR1 = 956,
|
||||
SPR_PMC3 = 957,
|
||||
SPR_PMC4 = 958,
|
||||
};
|
||||
|
||||
// Exceptions
|
||||
@@ -679,8 +723,9 @@ enum
|
||||
#define EXCEPTION_DSI 0x00000008
|
||||
#define EXCEPTION_ISI 0x00000010
|
||||
#define EXCEPTION_ALIGNMENT 0x00000020
|
||||
#define EXCEPTION_FPU_UNAVAILABLE 0x00000040
|
||||
#define EXCEPTION_FPU_UNAVAILABLE 0x00000040
|
||||
#define EXCEPTION_PROGRAM 0x00000080
|
||||
#define EXCEPTION_PERFORMANCE_MONITOR 0x00000100
|
||||
|
||||
inline s32 SignExt16(s16 x) {return (s32)(s16)x;}
|
||||
inline s32 SignExt26(u32 x) {return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x);}
|
||||
|
||||
@@ -42,10 +42,6 @@ using namespace MathUtil;
|
||||
|
||||
void UpdateSSEState();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma float_control(precise, on, push)
|
||||
#endif
|
||||
|
||||
// Extremely rare - actually, never seen.
|
||||
// Star Wars : Rogue Leader spams that at some point :|
|
||||
void Interpreter::Helper_UpdateCR1(double _fValue)
|
||||
@@ -518,8 +514,4 @@ void Interpreter::fsqrtx(UGeckoInstruction _inst)
|
||||
rPS0(_inst.FD) = sqrt(b);
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD));
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma float_control(pop)
|
||||
#endif
|
||||
}
|
||||
@@ -363,28 +363,34 @@ void Interpreter::dcbf(UGeckoInstruction _inst)
|
||||
{
|
||||
NPC = PC + 12;
|
||||
}*/
|
||||
// Invalidate the icache on dcbf
|
||||
// Invalidate the jit block cache on dcbf
|
||||
if (jit)
|
||||
{
|
||||
u32 address = Helper_Get_EA_X(_inst);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::dcbi(UGeckoInstruction _inst)
|
||||
{
|
||||
// Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache
|
||||
// However, we invalidate the icache on dcbi
|
||||
// However, we invalidate the jit block cache on dcbi
|
||||
if (jit)
|
||||
{
|
||||
u32 address = Helper_Get_EA_X(_inst);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::dcbst(UGeckoInstruction _inst)
|
||||
{
|
||||
// Cache line flush. Since we don't emulate the data cache, we don't need to do anything.
|
||||
// Invalidate the jit block cache on dcbst in case new code has been loaded via the data cache
|
||||
if (jit)
|
||||
{
|
||||
u32 address = Helper_Get_EA_X(_inst);
|
||||
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::dcbt(UGeckoInstruction _inst)
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
#include "JitAsm.h"
|
||||
#include "JitRegCache.h"
|
||||
#include "Jit64_Tables.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#include "PowerPCDisasm.h"
|
||||
#endif
|
||||
|
||||
using namespace Gen;
|
||||
using namespace PowerPC;
|
||||
@@ -187,12 +191,7 @@ void Jit64::Init()
|
||||
else
|
||||
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
|
||||
}
|
||||
#ifdef _M_X64
|
||||
jo.enableFastMem = Core::g_CoreStartupParameter.bUseFastMem;
|
||||
#else
|
||||
jo.enableFastMem = false;
|
||||
#endif
|
||||
jo.assumeFPLoadFromMem = Core::g_CoreStartupParameter.bUseFastMem;
|
||||
|
||||
jo.fpAccurateFcmp = true; // Fallback to Interpreter
|
||||
jo.optimizeGatherPipe = true;
|
||||
jo.fastInterrupts = false;
|
||||
@@ -296,6 +295,10 @@ void Jit64::Cleanup()
|
||||
{
|
||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
||||
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
|
||||
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst);
|
||||
}
|
||||
|
||||
void Jit64::WriteExit(u32 destination, int exit_num)
|
||||
@@ -334,16 +337,31 @@ void Jit64::WriteExitDestInEAX()
|
||||
void Jit64::WriteRfiExitDestInEAX()
|
||||
{
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
Cleanup();
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
JMP(asm_routines.testExceptions, true);
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
|
||||
void Jit64::WriteExceptionExit()
|
||||
{
|
||||
Cleanup();
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
JMP(asm_routines.testExceptions, true);
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
|
||||
void Jit64::WriteExternalExceptionExit()
|
||||
{
|
||||
Cleanup();
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions));
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
|
||||
void STACKALIGN Jit64::Run()
|
||||
@@ -412,15 +430,18 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
// Comment out the following to disable breakpoints (speed-up)
|
||||
blockSize = 1;
|
||||
broken_block = true;
|
||||
Trace();
|
||||
if (!Profiler::g_ProfileBlocks)
|
||||
{
|
||||
if (GetState() == CPU_STEPPING)
|
||||
blockSize = 1;
|
||||
Trace();
|
||||
}
|
||||
}
|
||||
|
||||
if (em_address == 0)
|
||||
{
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
PanicAlert("ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR);
|
||||
// Memory exception occurred during instruction fetch
|
||||
memory_exception = true;
|
||||
}
|
||||
|
||||
if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
|
||||
@@ -433,12 +454,15 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
js.firstFPInstructionFound = false;
|
||||
js.isLastInstruction = false;
|
||||
js.blockStart = em_address;
|
||||
js.fifoBytesThisBlock = 0;
|
||||
js.curBlock = b;
|
||||
js.block_flags = 0;
|
||||
js.cancel = false;
|
||||
jit->js.numLoadStoreInst = 0;
|
||||
jit->js.numFloatingPointInst = 0;
|
||||
|
||||
// Analyze the block, collect all instructions it is made of (including inlining,
|
||||
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
||||
@@ -470,16 +494,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
if (ImHereDebug)
|
||||
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
|
||||
|
||||
if (js.fpa.any)
|
||||
{
|
||||
// This block uses FPU - needs to add FP exception bailout
|
||||
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
|
||||
FixupBranch b1 = J_CC(CC_NZ);
|
||||
MOV(32, M(&PC), Imm32(js.blockStart));
|
||||
JMP(asm_routines.fpException, true);
|
||||
SetJumpTarget(b1);
|
||||
}
|
||||
|
||||
// Conditionally add profiling code.
|
||||
if (Profiler::g_ProfileBlocks) {
|
||||
ADD(32, M(&b->runCount), Imm8(1));
|
||||
@@ -555,18 +569,62 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
|
||||
if (!ops[i].skip)
|
||||
{
|
||||
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
|
||||
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
|
||||
{
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
||||
//This instruction uses FPU - needs to add FP exception bailout
|
||||
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
|
||||
FixupBranch b1 = J_CC(CC_NZ);
|
||||
FixupBranch b1 = J_CC(CC_NZ, true);
|
||||
|
||||
// If a FPU exception occurs, the exception handler will read
|
||||
// from PC. Update PC with the latest value in case that happens.
|
||||
MOV(32, M(&PC), Imm32(ops[i].address));
|
||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
JMP(asm_routines.fpException, true);
|
||||
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
||||
WriteExceptionExit();
|
||||
|
||||
SetJumpTarget(b1);
|
||||
|
||||
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);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
||||
MOV(32, M(&PC), Imm32(ops[i].address));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
|
||||
WriteExit(ops[i].address, 0);
|
||||
SetJumpTarget(noBreakpoint);
|
||||
}
|
||||
|
||||
Jit64Tables::CompileInstruction(ops[i]);
|
||||
@@ -578,7 +636,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
|
||||
FixupBranch noMemException = J_CC(CC_Z);
|
||||
FixupBranch noMemException = J_CC(CC_Z, true);
|
||||
|
||||
// If a memory exception occurs, the exception handler will read
|
||||
// from PC. Update PC with the latest value in case that happens.
|
||||
@@ -586,6 +644,12 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
WriteExceptionExit();
|
||||
SetJumpTarget(noMemException);
|
||||
}
|
||||
|
||||
if (opinfo->flags & FL_LOADSTORE)
|
||||
++jit->js.numLoadStoreInst;
|
||||
|
||||
if (opinfo->flags & FL_USE_FPU)
|
||||
++jit->js.numFloatingPointInst;
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
@@ -596,7 +660,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
NOTICE_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (js.skipnext) {
|
||||
js.skipnext = false;
|
||||
i++; // Skip next instruction
|
||||
@@ -610,6 +673,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
MOV(32, M(&NPC), Imm32(js.compilerPC));
|
||||
|
||||
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI));
|
||||
|
||||
// Remove the invalid instruction from the icache, forcing a recompile
|
||||
|
||||
@@ -65,32 +65,6 @@
|
||||
class Jit64 : public JitBase
|
||||
{
|
||||
private:
|
||||
struct JitState
|
||||
{
|
||||
u32 compilerPC;
|
||||
u32 next_compilerPC;
|
||||
u32 blockStart;
|
||||
bool cancel;
|
||||
bool skipnext;
|
||||
UGeckoInstruction next_inst; // for easy peephole opt.
|
||||
int blockSize;
|
||||
int instructionNumber;
|
||||
int downcountAmount;
|
||||
int block_flags;
|
||||
|
||||
bool isLastInstruction;
|
||||
bool memcheck;
|
||||
|
||||
int fifoBytesThisBlock;
|
||||
|
||||
PPCAnalyst::BlockStats st;
|
||||
PPCAnalyst::BlockRegStats gpa;
|
||||
PPCAnalyst::BlockRegStats fpa;
|
||||
PPCAnalyst::CodeOp *op;
|
||||
|
||||
JitBlock *curBlock;
|
||||
};
|
||||
|
||||
GPRRegCache gpr;
|
||||
FPURegCache fpr;
|
||||
|
||||
@@ -103,8 +77,6 @@ public:
|
||||
Jit64() : code_buffer(32000) {}
|
||||
~Jit64() {}
|
||||
|
||||
JitState js;
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
@@ -143,6 +115,7 @@ public:
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteExitDestInEAX();
|
||||
void WriteExceptionExit();
|
||||
void WriteExternalExceptionExit();
|
||||
void WriteRfiExitDestInEAX();
|
||||
void WriteCallInterpreter(UGeckoInstruction _inst);
|
||||
void Cleanup();
|
||||
|
||||
@@ -210,7 +210,7 @@ static GekkoOPTemplate table31[] =
|
||||
{824, &Jit64::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{24, &Jit64::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
|
||||
{54, &Jit64::DoNothing}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
|
||||
{54, &Jit64::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
|
||||
{86, &Jit64::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
|
||||
{246, &Jit64::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
|
||||
{278, &Jit64::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
|
||||
|
||||
@@ -70,7 +70,7 @@ void Jit64AsmRoutineManager::Generate()
|
||||
MOV(64, R(R15), Imm64((u64)jit->GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough
|
||||
#endif
|
||||
|
||||
const u8 *outerLoop = GetCodePtr();
|
||||
outerLoop = GetCodePtr();
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
|
||||
|
||||
@@ -81,12 +81,15 @@ void Jit64AsmRoutineManager::Generate()
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING));
|
||||
FixupBranch notStepping = J_CC(CC_Z);
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||
RET();
|
||||
SetJumpTarget(noBreakpoint);
|
||||
SetJumpTarget(notStepping);
|
||||
}
|
||||
|
||||
SetJumpTarget(skipToRealDispatch);
|
||||
@@ -191,27 +194,17 @@ void Jit64AsmRoutineManager::Generate()
|
||||
#endif
|
||||
JMP(dispatcherNoCheck); // no point in special casing this
|
||||
|
||||
//FP blocks test for FPU available, jump here if false
|
||||
fpException = AlignCode4();
|
||||
LOCK();
|
||||
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
JMP(dispatcher, true);
|
||||
|
||||
SetJumpTarget(bail);
|
||||
doTiming = GetCodePtr();
|
||||
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||
|
||||
testExceptions = GetCodePtr();
|
||||
testExternalExceptions = GetCodePtr();
|
||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT | EXCEPTION_PERFORMANCE_MONITOR | EXCEPTION_DECREMENTER));
|
||||
FixupBranch noExtException = J_CC(CC_Z);
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions));
|
||||
SetJumpTarget(noExtException);
|
||||
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
J_CC(CC_Z, outerLoop, true);
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ void Jit64::reg_imm(UGeckoInstruction inst)
|
||||
case 15:
|
||||
if (a == 0) { // lis
|
||||
// Merge with next instruction if loading a 32-bits immediate value (lis + addi, lis + ori)
|
||||
if (!js.isLastInstruction) {
|
||||
if (!js.isLastInstruction && !Core::g_CoreStartupParameter.bEnableDebugging) {
|
||||
if ((js.next_inst.OPCD == 14) && (js.next_inst.RD == d) && (js.next_inst.RA == d)) { // addi
|
||||
gpr.SetImmediate32(d, ((u32)inst.SIMM_16 << 16) + (u32)(s32)js.next_inst.SIMM_16);
|
||||
js.downcountAmount++;
|
||||
|
||||
@@ -151,7 +151,7 @@ void Jit64::lXXx(UGeckoInstruction inst)
|
||||
|
||||
// ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0
|
||||
//MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC));
|
||||
JMP(asm_routines.testExceptions, true);
|
||||
WriteExceptionExit();
|
||||
|
||||
SetJumpTarget(noIdle);
|
||||
|
||||
@@ -352,8 +352,8 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||
}
|
||||
|
||||
/* // TODO - figure out why Beyond Good and Evil hates this
|
||||
#ifdef _M_X64
|
||||
if (accessSize == 32 && !update && jo.enableFastMem)
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
if (accessSize == 32 && !update)
|
||||
{
|
||||
// Fast and daring - requires 64-bit
|
||||
MOV(32, R(EAX), gpr.R(s));
|
||||
@@ -405,10 +405,13 @@ void Jit64::stXx(UGeckoInstruction inst)
|
||||
gpr.Lock(a, b, s);
|
||||
gpr.FlushLockX(ECX, EDX);
|
||||
|
||||
if (inst.SUBOP10 & 32) {
|
||||
if (inst.SUBOP10 & 32)
|
||||
{
|
||||
MEMCHECK_START
|
||||
gpr.BindToRegister(a, true, true);
|
||||
ADD(32, gpr.R(a), gpr.R(b));
|
||||
MOV(32, R(EDX), gpr.R(a));
|
||||
MEMCHECK_END
|
||||
} else {
|
||||
MOV(32, R(EDX), gpr.R(a));
|
||||
ADD(32, R(EDX), gpr.R(b));
|
||||
@@ -425,12 +428,6 @@ void Jit64::stXx(UGeckoInstruction inst)
|
||||
MOV(32, R(ECX), gpr.R(s));
|
||||
SafeWriteRegToReg(ECX, EDX, accessSize, 0);
|
||||
|
||||
//MEMCHECK_START
|
||||
|
||||
// TODO: Insert rA update code here
|
||||
|
||||
//MEMCHECK_END
|
||||
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
}
|
||||
@@ -438,6 +435,9 @@ void Jit64::stXx(UGeckoInstruction inst)
|
||||
// A few games use these heavily in video codecs.
|
||||
void Jit64::lmw(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(LoadStore)
|
||||
|
||||
#ifdef _M_X64
|
||||
gpr.FlushLockX(ECX);
|
||||
MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16));
|
||||
@@ -458,6 +458,9 @@ void Jit64::lmw(UGeckoInstruction inst)
|
||||
|
||||
void Jit64::stmw(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(LoadStore)
|
||||
|
||||
#ifdef _M_X64
|
||||
gpr.FlushLockX(ECX);
|
||||
MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16));
|
||||
|
||||
@@ -62,14 +62,11 @@ void Jit64::lfs(UGeckoInstruction inst)
|
||||
return;
|
||||
}
|
||||
s32 offset = (s32)(s16)inst.SIMM_16;
|
||||
if (jo.assumeFPLoadFromMem)
|
||||
{
|
||||
UnsafeLoadToEAX(gpr.R(a), 32, offset, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SafeLoadToEAX(gpr.R(a), 32, offset, false);
|
||||
}
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
UnsafeLoadToEAX(gpr.R(a), 32, offset, false);
|
||||
#else
|
||||
SafeLoadToEAX(gpr.R(a), 32, offset, false);
|
||||
#endif
|
||||
|
||||
MEMCHECK_START
|
||||
|
||||
@@ -219,7 +216,7 @@ void Jit64::stfd(UGeckoInstruction inst)
|
||||
MOVD_xmm(R(EAX), XMM0);
|
||||
UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0);
|
||||
}
|
||||
FixupBranch exit = J();
|
||||
FixupBranch exit = J(true);
|
||||
SetJumpTarget(safe);
|
||||
|
||||
// Safe but slow routine
|
||||
@@ -240,7 +237,14 @@ void Jit64::stfd(UGeckoInstruction inst)
|
||||
fpr.UnlockAll();
|
||||
}
|
||||
|
||||
|
||||
// In Release on 32bit build,
|
||||
// this seemed to cause a problem with PokePark2
|
||||
// at start after talking to first pokemon,
|
||||
// you run and smash a box, then he goes on about
|
||||
// following him and then you cant do anything.
|
||||
// I have enabled interpreter for this function
|
||||
// in the mean time.
|
||||
// Parlane
|
||||
void Jit64::stfs(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
|
||||
@@ -93,6 +93,10 @@ void Jit64::mfspr(UGeckoInstruction inst)
|
||||
case SPR_DEC:
|
||||
case SPR_TL:
|
||||
case SPR_TU:
|
||||
case SPR_PMC1:
|
||||
case SPR_PMC2:
|
||||
case SPR_PMC3:
|
||||
case SPR_PMC4:
|
||||
Default(inst);
|
||||
return;
|
||||
default:
|
||||
@@ -119,6 +123,7 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
js.firstFPInstructionFound = false;
|
||||
}
|
||||
|
||||
void Jit64::mfmsr(UGeckoInstruction inst)
|
||||
|
||||
@@ -1212,7 +1212,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
|
||||
}
|
||||
|
||||
bool IRBuilder::maskedValueIsZero(InstLoc Op1, InstLoc Op2) const {
|
||||
return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op1)) == 0;
|
||||
return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op2)) == 0;
|
||||
}
|
||||
|
||||
// Returns I' if I == (0 - I')
|
||||
@@ -1260,16 +1260,17 @@ static const std::string opcodeNames[] = {
|
||||
"FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg",
|
||||
"FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit",
|
||||
"InterpreterBranch", "IdleBranch", "ShortIdleLoop",
|
||||
"FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "Tramp",
|
||||
"BlockStart", "BlockEnd", "Int3",
|
||||
"FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "ExtExceptionCheck",
|
||||
"Tramp", "BlockStart", "BlockEnd", "Int3",
|
||||
};
|
||||
static const unsigned alwaysUsedList[] = {
|
||||
InterpreterFallback, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR,
|
||||
StoreGQR, StoreSRR, StoreCarry, StoreFPRF, Load8, Load16, Load32, Store8,
|
||||
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
|
||||
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
|
||||
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart,
|
||||
FPExceptionCheckEnd, ISIException, Int3, Tramp, Nop
|
||||
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck,
|
||||
DSIExceptionCheck, ISIException, ExtExceptionCheck, BreakPointCheck,
|
||||
Int3, Tramp, Nop
|
||||
};
|
||||
static const unsigned extra8RegList[] = {
|
||||
LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero,
|
||||
|
||||
@@ -165,10 +165,10 @@ enum Opcode {
|
||||
ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
|
||||
// just a branch
|
||||
|
||||
// used for MMU, at least until someone
|
||||
// used for exception checking, at least until someone
|
||||
// has a better idea of integrating it
|
||||
FPExceptionCheckStart, FPExceptionCheckEnd,
|
||||
ISIException,
|
||||
FPExceptionCheck, DSIExceptionCheck,
|
||||
ISIException, ExtExceptionCheck, BreakPointCheck,
|
||||
// "Opcode" representing a register too far away to
|
||||
// reference directly; this is a size optimization
|
||||
Tramp,
|
||||
@@ -402,15 +402,21 @@ public:
|
||||
InstLoc EmitSystemCall(InstLoc pc) {
|
||||
return FoldUOp(SystemCall, pc);
|
||||
}
|
||||
InstLoc EmitFPExceptionCheckStart(InstLoc pc) {
|
||||
return EmitUOp(FPExceptionCheckStart, pc);
|
||||
InstLoc EmitFPExceptionCheck(InstLoc pc) {
|
||||
return EmitUOp(FPExceptionCheck, pc);
|
||||
}
|
||||
InstLoc EmitFPExceptionCheckEnd(InstLoc pc) {
|
||||
return EmitUOp(FPExceptionCheckEnd, pc);
|
||||
InstLoc EmitDSIExceptionCheck(InstLoc pc) {
|
||||
return EmitUOp(DSIExceptionCheck, pc);
|
||||
}
|
||||
InstLoc EmitISIException(InstLoc dest) {
|
||||
return EmitUOp(ISIException, dest);
|
||||
}
|
||||
InstLoc EmitExtExceptionCheck(InstLoc pc) {
|
||||
return EmitUOp(ExtExceptionCheck, pc);
|
||||
}
|
||||
InstLoc EmitBreakPointCheck(InstLoc pc) {
|
||||
return EmitUOp(BreakPointCheck, pc);
|
||||
}
|
||||
InstLoc EmitRFIExit() {
|
||||
return FoldZeroOp(RFIExit, 0);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ The register allocation is linear scan allocation.
|
||||
#include "../../../../Common/Src/CPUDetect.h"
|
||||
#include "MathUtil.h"
|
||||
#include "../../Core.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
|
||||
static ThunkManager thunks;
|
||||
|
||||
@@ -758,9 +759,11 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
case RFIExit:
|
||||
case InterpreterBranch:
|
||||
case ShortIdleLoop:
|
||||
case FPExceptionCheckStart:
|
||||
case FPExceptionCheckEnd:
|
||||
case FPExceptionCheck:
|
||||
case DSIExceptionCheck:
|
||||
case ISIException:
|
||||
case ExtExceptionCheck:
|
||||
case BreakPointCheck:
|
||||
case Int3:
|
||||
case Tramp:
|
||||
// No liveness effects
|
||||
@@ -1385,7 +1388,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I)));
|
||||
RI.Jit->UnsafeWriteRegToReg(EAX, ECX, 32, 0);
|
||||
}
|
||||
FixupBranch exit = Jit->J();
|
||||
FixupBranch exit = Jit->J(true);
|
||||
Jit->SetJumpTarget(safe);
|
||||
// Safe but slow routine
|
||||
OpArg value = fregLocForInst(RI, getOp1(I));
|
||||
@@ -1866,7 +1869,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
Jit->WriteRfiExitDestInOpArg(R(EAX));
|
||||
break;
|
||||
}
|
||||
case FPExceptionCheckStart: {
|
||||
case FPExceptionCheck: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
//This instruction uses FPU - needs to add FP exception bailout
|
||||
Jit->TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
|
||||
@@ -1880,7 +1883,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||
Jit->SetJumpTarget(b1);
|
||||
break;
|
||||
}
|
||||
case FPExceptionCheckEnd: {
|
||||
case DSIExceptionCheck: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
|
||||
FixupBranch noMemException = Jit->J_CC(CC_Z);
|
||||
@@ -1920,6 +1923,38 @@ 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));
|
||||
|
||||
Jit->MOV(32, M(&PC), Imm32(InstLoc));
|
||||
Jit->ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
Jit->TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = Jit->J_CC(CC_Z);
|
||||
Jit->WriteExit(InstLoc, 0);
|
||||
Jit->SetJumpTarget(noBreakpoint);
|
||||
break;
|
||||
}
|
||||
case Int3: {
|
||||
Jit->INT3();
|
||||
break;
|
||||
|
||||
@@ -276,12 +276,6 @@ void JitIL::Init()
|
||||
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
|
||||
}
|
||||
|
||||
#ifdef _M_X64
|
||||
jo.enableFastMem = false;
|
||||
#else
|
||||
jo.enableFastMem = false;
|
||||
#endif
|
||||
jo.assumeFPLoadFromMem = Core::g_CoreStartupParameter.bUseFastMem;
|
||||
jo.fpAccurateFcmp = false;
|
||||
jo.optimizeGatherPipe = true;
|
||||
jo.fastInterrupts = false;
|
||||
@@ -396,6 +390,10 @@ void JitIL::Cleanup()
|
||||
{
|
||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
||||
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
|
||||
|
||||
// SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time.
|
||||
if (MMCR0.Hex || MMCR1.Hex)
|
||||
ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst);
|
||||
}
|
||||
|
||||
void JitIL::WriteExit(u32 destination, int exit_num)
|
||||
@@ -524,12 +522,19 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
// Comment out the following to disable breakpoints (speed-up)
|
||||
blockSize = 1;
|
||||
Trace();
|
||||
if (!Profiler::g_ProfileBlocks)
|
||||
{
|
||||
if (GetState() == CPU_STEPPING)
|
||||
blockSize = 1;
|
||||
Trace();
|
||||
}
|
||||
}
|
||||
|
||||
if (em_address == 0)
|
||||
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
||||
{
|
||||
// Memory exception occurred during instruction fetch
|
||||
memory_exception = true;
|
||||
}
|
||||
|
||||
if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
|
||||
{
|
||||
@@ -546,6 +551,8 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
js.fifoBytesThisBlock = 0;
|
||||
js.curBlock = b;
|
||||
js.cancel = false;
|
||||
jit->js.numLoadStoreInst = 0;
|
||||
jit->js.numFloatingPointInst = 0;
|
||||
|
||||
// Analyze the block, collect all instructions it is made of (including inlining,
|
||||
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
||||
@@ -646,15 +653,31 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
{
|
||||
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
|
||||
{
|
||||
ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address));
|
||||
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));
|
||||
}
|
||||
|
||||
JitILTables::CompileInstruction(ops[i]);
|
||||
|
||||
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
|
||||
{
|
||||
ibuild.EmitFPExceptionCheckEnd(ibuild.EmitIntConst(ops[i].address));
|
||||
ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
if (opinfo->flags & FL_LOADSTORE)
|
||||
++jit->js.numLoadStoreInst;
|
||||
|
||||
if (opinfo->flags & FL_USE_FPU)
|
||||
++jit->js.numFloatingPointInst;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,12 +83,15 @@ void JitILAsmRoutineManager::Generate()
|
||||
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING));
|
||||
FixupBranch notStepping = J_CC(CC_Z);
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||
RET();
|
||||
SetJumpTarget(noBreakpoint);
|
||||
SetJumpTarget(notStepping);
|
||||
}
|
||||
|
||||
SetJumpTarget(skipToRealDispatch);
|
||||
@@ -208,14 +211,14 @@ void JitILAsmRoutineManager::Generate()
|
||||
doTiming = GetCodePtr();
|
||||
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||
|
||||
|
||||
testExceptions = GetCodePtr();
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
|
||||
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
J_CC(CC_Z, outerLoop, true);
|
||||
//Landing pad for drec space
|
||||
|
||||
@@ -493,6 +493,9 @@ void JitIL::srawx(UGeckoInstruction inst)
|
||||
test = ibuild.EmitOr(val, mask2);
|
||||
test = ibuild.EmitICmpUgt(test, mask);
|
||||
ibuild.EmitStoreCarry(test);
|
||||
|
||||
if (inst.Rc)
|
||||
ComputeRC(ibuild, val);
|
||||
}
|
||||
|
||||
void JitIL::srawix(UGeckoInstruction inst)
|
||||
|
||||
@@ -212,7 +212,7 @@ static GekkoOPTemplate table31[] =
|
||||
{824, &JitIL::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
{24, &JitIL::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
|
||||
|
||||
{54, &JitIL::DoNothing}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
|
||||
{54, &JitIL::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
|
||||
{86, &JitIL::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
|
||||
{246, &JitIL::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
|
||||
{278, &JitIL::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
|
||||
|
||||
@@ -40,12 +40,14 @@ public:
|
||||
|
||||
const u8 *enterCode;
|
||||
|
||||
const u8 *outerLoop;
|
||||
const u8 *dispatcher;
|
||||
const u8 *dispatcherNoCheck;
|
||||
const u8 *dispatcherPcInEAX;
|
||||
|
||||
const u8 *fpException;
|
||||
const u8 *testExceptions;
|
||||
const u8 *testExternalExceptions;
|
||||
const u8 *dispatchPcInEAX;
|
||||
const u8 *doTiming;
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
#include "JitBase.h"
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "disasm.h"
|
||||
|
||||
JitBase *jit;
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
#include "JitBackpatch.h" // for EmuCodeBlock
|
||||
#include "JitAsmCommon.h"
|
||||
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "disasm.h"
|
||||
#include <set>
|
||||
|
||||
#define JIT_OPCODE 0
|
||||
|
||||
@@ -42,10 +41,8 @@ protected:
|
||||
struct JitOptions
|
||||
{
|
||||
bool optimizeStack;
|
||||
bool assumeFPLoadFromMem;
|
||||
bool enableBlocklink;
|
||||
bool fpAccurateFcmp;
|
||||
bool enableFastMem;
|
||||
bool optimizeGatherPipe;
|
||||
bool fastInterrupts;
|
||||
bool accurateSinglePrecision;
|
||||
@@ -60,11 +57,16 @@ protected:
|
||||
int blockSize;
|
||||
int instructionNumber;
|
||||
int downcountAmount;
|
||||
u32 numLoadStoreInst;
|
||||
u32 numFloatingPointInst;
|
||||
|
||||
bool firstFPInstructionFound;
|
||||
bool isLastInstruction;
|
||||
bool forceUnsafeLoad;
|
||||
bool memcheck;
|
||||
bool skipnext;
|
||||
bool broken_block;
|
||||
int block_flags;
|
||||
|
||||
int fifoBytesThisBlock;
|
||||
|
||||
@@ -75,6 +77,8 @@ protected:
|
||||
u8* rewriteStart;
|
||||
|
||||
JitBlock *curBlock;
|
||||
|
||||
std::set<u32> fifoWriteAddresses;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@@ -208,7 +208,11 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
JitBlock &b = blocks[block_num];
|
||||
b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress);
|
||||
Memory::Write_Opcode_JIT(b.originalAddress, (JIT_OPCODE << 26) | block_num);
|
||||
block_map[std::make_pair(b.originalAddress + 4 * b.originalSize - 1, b.originalAddress)] = block_num;
|
||||
|
||||
// Convert the logical address to a physical address for the block map
|
||||
u32 pAddr = b.originalAddress & 0x1FFFFFFF;
|
||||
|
||||
block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num;
|
||||
if (block_link)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
@@ -353,6 +357,24 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
}
|
||||
}
|
||||
|
||||
void JitBlockCache::UnlinkBlock(int i)
|
||||
{
|
||||
JitBlock &b = blocks[i];
|
||||
std::map<u32, int>::iterator iter;
|
||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||
ppp = links_to.equal_range(b.originalAddress);
|
||||
if (ppp.first == ppp.second)
|
||||
return;
|
||||
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
|
||||
JitBlock &sourceBlock = blocks[iter2->second];
|
||||
for (int e = 0; e < 2; e++)
|
||||
{
|
||||
if (sourceBlock.exitAddress[e] == b.originalAddress)
|
||||
sourceBlock.linkStatus[e] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
|
||||
{
|
||||
if (block_num < 0 || block_num >= num_blocks)
|
||||
@@ -375,7 +397,9 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
||||
#endif
|
||||
|
||||
// We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher.
|
||||
UnlinkBlock(block_num);
|
||||
|
||||
// Send anyone who tries to run this block back to the dispatcher.
|
||||
// Not entirely ideal, but .. pretty good.
|
||||
// Spurious entrances from previously linked blocks can only come through checkedEntry
|
||||
XEmitter emit((u8 *)b.checkedEntry);
|
||||
@@ -389,16 +413,38 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void JitBlockCache::InvalidateICache(u32 address)
|
||||
void JitBlockCache::InvalidateICache(u32 address, const u32 length)
|
||||
{
|
||||
address &= ~0x1f;
|
||||
// Convert the logical address to a physical address for the block map
|
||||
u32 pAddr = address & 0x1FFFFFFF;
|
||||
|
||||
// destroy JIT blocks
|
||||
// !! this works correctly under assumption that any two overlapping blocks end at the same address
|
||||
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it;
|
||||
while (it2 != block_map.end() && it2->first.second < address + 0x20)
|
||||
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1, it;
|
||||
while (it2 != block_map.end() && it2->first.second < pAddr + length)
|
||||
{
|
||||
DestroyBlock(it2->second, true);
|
||||
#ifdef JIT_UNLIMITED_ICACHE
|
||||
JitBlock &b = blocks[it2->second];
|
||||
if (b.originalFirstOpcode != Memory::ReadUnchecked_U32(b.originalAddress))
|
||||
{
|
||||
if (b.originalAddress & JIT_ICACHE_VMEM_BIT)
|
||||
{
|
||||
u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK;
|
||||
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
|
||||
}
|
||||
else if (b.originalAddress & JIT_ICACHE_EXRAM_BIT)
|
||||
{
|
||||
u32 cacheaddr = b.originalAddress & JIT_ICACHEEX_MASK;
|
||||
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK;
|
||||
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
|
||||
}
|
||||
#endif
|
||||
DestroyBlock(it2->second, true);
|
||||
}
|
||||
it2++;
|
||||
}
|
||||
if (it1 != it2)
|
||||
@@ -418,17 +464,17 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
||||
if (address & JIT_ICACHE_VMEM_BIT)
|
||||
{
|
||||
u32 cacheaddr = address & JIT_ICACHE_MASK;
|
||||
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
|
||||
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
|
||||
}
|
||||
else if (address & JIT_ICACHE_EXRAM_BIT)
|
||||
{
|
||||
u32 cacheaddr = address & JIT_ICACHEEX_MASK;
|
||||
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
|
||||
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 cacheaddr = address & JIT_ICACHE_MASK;
|
||||
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
|
||||
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ class JitBlockCache
|
||||
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
|
||||
void LinkBlockExits(int i);
|
||||
void LinkBlock(int i);
|
||||
void UnlinkBlock(int i);
|
||||
|
||||
public:
|
||||
JitBlockCache() :
|
||||
@@ -129,7 +130,7 @@ public:
|
||||
CompiledCode GetCompiledCodeFromBlock(int block_num);
|
||||
|
||||
// DOES NOT WORK CORRECTLY WITH INLINING
|
||||
void InvalidateICache(u32 em_address);
|
||||
void InvalidateICache(u32 address, const u32 length);
|
||||
void DestroyBlock(int block_num, bool invalidate);
|
||||
|
||||
// Not currently used
|
||||
|
||||
@@ -118,16 +118,18 @@ void EmuCodeBlock::UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize,
|
||||
|
||||
void EmuCodeBlock::SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend)
|
||||
{
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
#ifdef ENABLE_MEM_CHECK
|
||||
if (Core::g_CoreStartupParameter.bUseFastMem && (accessSize == 32) && !Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
if (accessSize == 32 && !Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
#else
|
||||
if (Core::g_CoreStartupParameter.bUseFastMem && (accessSize == 32) && !Core::g_CoreStartupParameter.bMMU)
|
||||
if (accessSize == 32 && !Core::g_CoreStartupParameter.bMMU)
|
||||
#endif
|
||||
{
|
||||
// BackPatch only supports 32-bits accesses
|
||||
UnsafeLoadToEAX(opAddress, accessSize, offset, signExtend);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS;
|
||||
if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.iTLBHack)
|
||||
@@ -252,7 +254,7 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
||||
|
||||
TEST(32, R(reg_addr), Imm32(mem_mask));
|
||||
FixupBranch fast = J_CC(CC_Z);
|
||||
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
switch (accessSize)
|
||||
{
|
||||
case 32: ABI_CallFunctionRR(thunks.ProtectFunction(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), 2), reg_value, reg_addr); break;
|
||||
@@ -288,6 +290,7 @@ void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr)
|
||||
MOVSS(M(&float_buffer), xmm_value);
|
||||
MOV(32, R(EAX), M(&float_buffer));
|
||||
BSWAP(32, EAX);
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
ABI_CallFunctionRR(thunks.ProtectFunction(((void *)&Memory::Write_U32), 2), EAX, reg_addr);
|
||||
FixupBranch arg2 = J();
|
||||
SetJumpTarget(argh);
|
||||
|
||||
@@ -299,7 +299,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa,
|
||||
merged_addresses[0] = address;
|
||||
size_of_merged_addresses = 1;
|
||||
|
||||
memset(st, 0, sizeof(st));
|
||||
memset(st, 0, sizeof(*st));
|
||||
|
||||
// Disabled the following optimization in preference of FAST_ICACHE
|
||||
//UGeckoInstruction previnst = Memory::Read_Opcode_JIT_LC(address - 4);
|
||||
@@ -559,7 +559,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa,
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory exception occurred
|
||||
// ISI exception or other critical memory exception occurred (game over)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace PowerPC
|
||||
#endif
|
||||
valid[set] = 0;
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(addr);
|
||||
jit->GetBlockCache()->InvalidateICache(addr & ~0x1f, 32);
|
||||
}
|
||||
|
||||
u32 InstructionCache::ReadInstruction(u32 addr)
|
||||
|
||||
@@ -289,6 +289,65 @@ void Stop()
|
||||
Host_UpdateDisasmDialog();
|
||||
}
|
||||
|
||||
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst)
|
||||
{
|
||||
switch (MMCR0.PMC1SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC1] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR0.PMC2SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += cycles;
|
||||
break;
|
||||
case 11: // Number of loads and stores completed
|
||||
PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR1.PMC3SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += cycles;
|
||||
break;
|
||||
case 11: // Number of FPU instructions completed
|
||||
PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MMCR1.PMC4SELECT)
|
||||
{
|
||||
case 0: // No change
|
||||
break;
|
||||
case 1: // Processor cycles
|
||||
PowerPC::ppcState.spr[SPR_PMC4] += cycles;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) ||
|
||||
(MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0))
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
|
||||
}
|
||||
|
||||
void CheckExceptions()
|
||||
{
|
||||
// Make sure we are checking against the latest EXI status. This is required
|
||||
@@ -298,9 +357,6 @@ void CheckExceptions()
|
||||
// Read volatile data once
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
|
||||
if (!exceptions)
|
||||
return;
|
||||
|
||||
// Example procedure:
|
||||
// set SRR0 to either PC or NPC
|
||||
//SRR0 = NPC;
|
||||
@@ -311,7 +367,7 @@ void CheckExceptions()
|
||||
// clear MSR as specified
|
||||
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
|
||||
// set to exception type entry point
|
||||
//NPC = 0x80000x00;
|
||||
//NPC = 0x00000x00;
|
||||
|
||||
if (exceptions & EXCEPTION_ISI)
|
||||
{
|
||||
@@ -320,7 +376,7 @@ void CheckExceptions()
|
||||
SRR1 = (MSR & 0x87C0FFFF) | (1 << 30);
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000400;
|
||||
PC = NPC = 0x00000400;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_ISI");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ISI);
|
||||
@@ -332,7 +388,7 @@ void CheckExceptions()
|
||||
SRR1 = (MSR & 0x87C0FFFF) | 0x20000;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000700;
|
||||
PC = NPC = 0x00000700;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PROGRAM");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PROGRAM);
|
||||
@@ -343,7 +399,7 @@ void CheckExceptions()
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000C00;
|
||||
PC = NPC = 0x00000C00;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_SYSCALL);
|
||||
@@ -355,7 +411,7 @@ void CheckExceptions()
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000800;
|
||||
PC = NPC = 0x00000800;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_FPU_UNAVAILABLE);
|
||||
@@ -366,7 +422,7 @@ void CheckExceptions()
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000300;
|
||||
PC = NPC = 0x00000300;
|
||||
//DSISR and DAR regs are changed in GenerateDSIException()
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DSI");
|
||||
@@ -380,7 +436,7 @@ void CheckExceptions()
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000600;
|
||||
PC = NPC = 0x00000600;
|
||||
|
||||
//TODO crazy amount of DSISR options to check out
|
||||
|
||||
@@ -398,20 +454,78 @@ void CheckExceptions()
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000500;
|
||||
PC = NPC = 0x00000500;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
|
||||
|
||||
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PERFORMANCE_MONITOR);
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000900;
|
||||
PC = NPC = 0x00000900;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckExternalExceptions()
|
||||
{
|
||||
// Read volatile data once
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
|
||||
// EXTERNAL INTERRUPT
|
||||
if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...
|
||||
{
|
||||
if (exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000500;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
|
||||
|
||||
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000F00;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PERFORMANCE_MONITOR);
|
||||
}
|
||||
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 16) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
PC = NPC = 0x00000900;
|
||||
|
||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER);
|
||||
|
||||
@@ -102,6 +102,7 @@ void SetMode(CoreMode _coreType);
|
||||
|
||||
void SingleStep();
|
||||
void CheckExceptions();
|
||||
void CheckExternalExceptions();
|
||||
void CheckBreakPoints();
|
||||
void RunLoop();
|
||||
void Start();
|
||||
@@ -116,12 +117,16 @@ void ExpandCR();
|
||||
void OnIdle(u32 _uThreadAddr);
|
||||
void OnIdleIL();
|
||||
|
||||
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst);
|
||||
|
||||
// Easy register access macros.
|
||||
#define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0])
|
||||
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])
|
||||
#define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4])
|
||||
#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU])
|
||||
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL])
|
||||
#define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0])
|
||||
#define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1])
|
||||
#define PC PowerPC::ppcState.pc
|
||||
#define NPC PowerPC::ppcState.npc
|
||||
#define FPSCR ((UReg_FPSCR&)PowerPC::ppcState.fpscr)
|
||||
|
||||
@@ -56,18 +56,21 @@ void WriteProfileResults(const char *filename)
|
||||
for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++)
|
||||
{
|
||||
const JitBlock *block = jit->GetBlockCache()->GetBlock(i);
|
||||
// Rough heuristic. Mem instructions should cost more.
|
||||
u64 cost = block->originalSize * (block->runCount / 4);
|
||||
if (block && !block->invalid)
|
||||
{
|
||||
// Rough heuristic. Mem instructions should cost more.
|
||||
u64 cost = block->originalSize * (block->runCount / 4);
|
||||
#ifdef _WIN32
|
||||
u64 timecost = block->ticCounter;
|
||||
u64 timecost = block->ticCounter;
|
||||
#endif
|
||||
// Todo: tweak.
|
||||
if (block->runCount >= 1)
|
||||
stats.push_back(BlockStat(i, cost));
|
||||
cost_sum += cost;
|
||||
// Todo: tweak.
|
||||
if (block->runCount >= 1)
|
||||
stats.push_back(BlockStat(i, cost));
|
||||
cost_sum += cost;
|
||||
#ifdef _WIN32
|
||||
timecost_sum += timecost;
|
||||
timecost_sum += timecost;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sort(stats.begin(), stats.end());
|
||||
@@ -77,18 +80,18 @@ void WriteProfileResults(const char *filename)
|
||||
PanicAlert("failed to open %s", filename);
|
||||
return;
|
||||
}
|
||||
fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
|
||||
fprintf(f.GetHandle(), "origAddr\tblkName\tcost\trunCount\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
|
||||
for (unsigned int i = 0; i < stats.size(); i++)
|
||||
{
|
||||
const JitBlock *block = jit->GetBlockCache()->GetBlock(stats[i].blockNum);
|
||||
if (block)
|
||||
if (block && !block->invalid)
|
||||
{
|
||||
std::string name = g_symbolDB.GetDescription(block->originalAddress);
|
||||
double percent = 100.0 * (double)stats[i].cost / (double)cost_sum;
|
||||
#ifdef _WIN32
|
||||
double timePercent = 100.0 * (double)block->ticCounter / (double)timecost_sum;
|
||||
fprintf(f.GetHandle(), "%08x\t%s\t%llu\t%llu\t%.2lf\t%llf\t%lf\t%i\n",
|
||||
block->originalAddress, name.c_str(), stats[i].cost,
|
||||
fprintf(f.GetHandle(), "%08x\t%s\t%llu\t%llu\t%llu\t%.2lf\t%llf\t%lf\t%i\n",
|
||||
block->originalAddress, name.c_str(), stats[i].cost, block->runCount,
|
||||
block->ticCounter, percent, timePercent,
|
||||
(double)block->ticCounter*1000.0/(double)countsPerSec, block->codeSize);
|
||||
#else
|
||||
|
||||
@@ -3,6 +3,7 @@ set(SRCS Src/BannerLoader.cpp
|
||||
Src/BannerLoaderWii.cpp
|
||||
Src/Blob.cpp
|
||||
Src/CISOBlob.cpp
|
||||
Src/WbfsBlob.cpp
|
||||
Src/CompressedBlob.cpp
|
||||
Src/DiscScrubber.cpp
|
||||
Src/DriveBlob.cpp
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
<ClInclude Include="Src\BannerLoaderWii.h" />
|
||||
<ClInclude Include="Src\Blob.h" />
|
||||
<ClInclude Include="Src\CISOBlob.h" />
|
||||
<ClInclude Include="Src\WbfsBlob.h" />
|
||||
<ClInclude Include="Src\CompressedBlob.h" />
|
||||
<ClInclude Include="Src\DiscScrubber.h" />
|
||||
<ClInclude Include="Src\DriveBlob.h" />
|
||||
@@ -199,6 +200,7 @@
|
||||
<ClCompile Include="Src\BannerLoaderWii.cpp" />
|
||||
<ClCompile Include="Src\Blob.cpp" />
|
||||
<ClCompile Include="Src\CISOBlob.cpp" />
|
||||
<ClCompile Include="Src\WbfsBlob.cpp" />
|
||||
<ClCompile Include="Src\CompressedBlob.cpp" />
|
||||
<ClCompile Include="Src\DiscScrubber.cpp" />
|
||||
<ClCompile Include="Src\DriveBlob.cpp" />
|
||||
@@ -226,7 +228,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
<None Include="Src\SConscript" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
<ClCompile Include="Src\CISOBlob.cpp">
|
||||
<Filter>Volume\Blob</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\WbfsBlob.cpp">
|
||||
<Filter>Volume\Blob</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\CompressedBlob.cpp">
|
||||
<Filter>Volume\Blob</Filter>
|
||||
</ClCompile>
|
||||
@@ -71,6 +74,9 @@
|
||||
<ClInclude Include="Src\CISOBlob.h">
|
||||
<Filter>Volume\Blob</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\WbfsBlob.h">
|
||||
<Filter>Volume\Blob</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\Blob.h">
|
||||
<Filter>Volume\Blob</Filter>
|
||||
</ClInclude>
|
||||
@@ -133,7 +139,6 @@
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Src\SConscript" />
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- python -*-
|
||||
|
||||
Import('env')
|
||||
|
||||
files = [
|
||||
'Src/BannerLoader.cpp',
|
||||
'Src/BannerLoaderGC.cpp',
|
||||
'Src/BannerLoaderWii.cpp',
|
||||
'Src/Blob.cpp',
|
||||
'Src/CISOBlob.cpp',
|
||||
'Src/CompressedBlob.cpp',
|
||||
'Src/DiscScrubber.cpp',
|
||||
'Src/DriveBlob.cpp',
|
||||
'Src/FileBlob.cpp',
|
||||
'Src/FileHandlerARC.cpp',
|
||||
'Src/FileMonitor.cpp',
|
||||
'Src/FileSystemGCWii.cpp',
|
||||
'Src/Filesystem.cpp',
|
||||
'Src/NANDContentLoader.cpp',
|
||||
'Src/VolumeCommon.cpp',
|
||||
'Src/VolumeCreator.cpp',
|
||||
'Src/VolumeDirectory.cpp',
|
||||
'Src/VolumeGC.cpp',
|
||||
'Src/VolumeWad.cpp',
|
||||
'Src/VolumeWiiCrypted.cpp',
|
||||
'Src/WiiWad.cpp',
|
||||
]
|
||||
|
||||
env['LIBS'] += env.StaticLibrary('discio', files)
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "FileBlob.h"
|
||||
#include "CISOBlob.h"
|
||||
#include "DriveBlob.h"
|
||||
#include "WbfsBlob.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
@@ -128,6 +129,9 @@ IBlobReader* CreateBlobReader(const char* filename)
|
||||
if (!File::Exists(filename))
|
||||
return 0;
|
||||
|
||||
if (IsWbfsBlob(filename))
|
||||
return WbfsFileReader::Create(filename);
|
||||
|
||||
if (IsCompressedBlob(filename))
|
||||
return CompressedBlobReader::Create(filename);
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ void cUIDsys::AddTitle(u64 _TitleID)
|
||||
File::CreateFullPath(uidSys);
|
||||
File::IOFile pFile(uidSys, "ab");
|
||||
|
||||
if (pFile.WriteArray(&Element, 1))
|
||||
if (!pFile.WriteArray(&Element, 1))
|
||||
ERROR_LOG(DISCIO, "fwrite failed");
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,11 @@ public:
|
||||
virtual std::string GetUniqueID() const = 0;
|
||||
virtual std::string GetMakerID() const = 0;
|
||||
virtual std::string GetName() const = 0;
|
||||
virtual bool GetWName(std::vector<std::wstring>& _rwNames) const {return false;};
|
||||
virtual bool GetWName(std::vector<std::wstring>& _rwNames) const { return false; }
|
||||
virtual u32 GetFSTSize() const = 0;
|
||||
virtual std::string GetApploaderDate() const = 0;
|
||||
virtual bool SupportsIntegrityCheck() const { return false; }
|
||||
virtual bool CheckIntegrity() const { return false; }
|
||||
|
||||
enum ECountry
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "MathUtil.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "VolumeDirectory.h"
|
||||
#include "FileBlob.h"
|
||||
@@ -23,17 +24,6 @@
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
static const u8 ENTRY_SIZE = 0x0c;
|
||||
static const u8 FILE_ENTRY = 0;
|
||||
static const u8 DIRECTORY_ENTRY = 1;
|
||||
static const u64 DISKHEADER_ADDRESS = 0;
|
||||
static const u64 DISKHEADERINFO_ADDRESS = 0x440;
|
||||
static const u64 APPLOADER_ADDRESS = 0x2440;
|
||||
static const u32 MAX_NAME_LENGTH = 0x3df;
|
||||
// relocatable
|
||||
static u64 FST_ADDRESS = 0x440;
|
||||
static u64 DOL_ADDRESS = 0;
|
||||
|
||||
CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii,
|
||||
const std::string& _rApploader, const std::string& _rDOL)
|
||||
: m_totalNameSize(0)
|
||||
@@ -44,6 +34,8 @@ CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii,
|
||||
, m_apploader(NULL)
|
||||
, m_DOLSize(0)
|
||||
, m_DOL(NULL)
|
||||
, FST_ADDRESS(0)
|
||||
, DOL_ADDRESS(0)
|
||||
{
|
||||
m_rootDirectory = ExtractDirectoryName(_rDirectory);
|
||||
|
||||
@@ -321,7 +313,7 @@ bool CVolumeDirectory::SetApploader(const std::string& _rApploader)
|
||||
copy(data.begin(), data.end(), m_apploader);
|
||||
|
||||
// 32byte aligned (plus 0x20 padding)
|
||||
DOL_ADDRESS = (APPLOADER_ADDRESS + m_apploaderSize + 0x20 + 31) & ~31ULL;
|
||||
DOL_ADDRESS = ROUND_UP(APPLOADER_ADDRESS + m_apploaderSize + 0x20, 0x20ull);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -347,7 +339,7 @@ void CVolumeDirectory::SetDOL(const std::string& _rDOL)
|
||||
Write32((u32)(DOL_ADDRESS >> m_addressShift), 0x0420, m_diskHeader);
|
||||
|
||||
// 32byte aligned (plus 0x20 padding)
|
||||
FST_ADDRESS = (DOL_ADDRESS + m_DOLSize + 0x20 + 31) & ~31ULL;
|
||||
FST_ADDRESS = ROUND_UP(DOL_ADDRESS + m_DOLSize + 0x20, 0x20ull);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,8 +359,12 @@ void CVolumeDirectory::BuildFST()
|
||||
m_fstSize = m_fstNameOffset + m_totalNameSize;
|
||||
m_FSTData = new u8[(u32)m_fstSize];
|
||||
|
||||
// if FST hasn't been assigned (ie no apploader/dol setup), set to default
|
||||
if (FST_ADDRESS == 0)
|
||||
FST_ADDRESS = APPLOADER_ADDRESS + 0x2000;
|
||||
|
||||
// 4 byte aligned start of data on disk
|
||||
m_dataStartAddress = (FST_ADDRESS + m_fstSize + 3) & ~3;
|
||||
m_dataStartAddress = ROUND_UP(FST_ADDRESS + m_fstSize, 0x8000ull);
|
||||
u64 curDataAddress = m_dataStartAddress;
|
||||
|
||||
u32 fstOffset = 0; // offset within FST data
|
||||
@@ -389,8 +385,8 @@ void CVolumeDirectory::BuildFST()
|
||||
// write FST size and location
|
||||
_dbg_assert_(DVDINTERFACE, m_diskHeader);
|
||||
Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x0428, m_diskHeader);
|
||||
Write32((u32)m_fstSize, 0x042c, m_diskHeader);
|
||||
Write32((u32)(m_fstSize >> m_addressShift), 0x0428, m_diskHeader);
|
||||
Write32((u32)(m_fstSize >> m_addressShift), 0x042c, m_diskHeader);
|
||||
}
|
||||
|
||||
void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, u8* _Src,
|
||||
@@ -490,7 +486,7 @@ void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u
|
||||
m_virtualDisk.insert(make_pair(dataOffset, entry.physicalName));
|
||||
|
||||
// 4 byte aligned
|
||||
dataOffset = (dataOffset + entry.size + 3) & ~3ULL;
|
||||
dataOffset = ROUND_UP(dataOffset + entry.size, 0x8000ull);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user