mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-28 01:49:33 -06:00
Initial megacommit.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
677
Source/Core/Common/Common.vcproj
Normal file
677
Source/Core/Common/Common.vcproj
Normal file
@ -0,0 +1,677 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="Common"
|
||||
ProjectGUID="{C573CAF7-EE6A-458E-8049-16C0BF34C2E9}"
|
||||
RootNamespace="Common"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_SECURE_SCL=0"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="wsock32.lib"
|
||||
OutputFile="$(OutDir)/Common.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_SECURE_SCL=0"
|
||||
StringPooling="true"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
BufferSecurityCheck="false"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="wsock32.lib"
|
||||
OutputFile="$(OutDir)/Common.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="2"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="true"
|
||||
EnableEnhancedInstructionSet="2"
|
||||
FloatingPointModel="2"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="wsock32.lib"
|
||||
OutputFile="$(OutDir)/Common.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_SECURE_SCL=0"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
EnableEnhancedInstructionSet="0"
|
||||
FloatingPointModel="2"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="wsock32.lib winmm.lib"
|
||||
OutputFile="$(OutDir)/Common.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugFast|Win32"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_SECURE_SCL=0"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="wsock32.lib"
|
||||
OutputFile="$(OutDir)/Common.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugFast|x64"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_SECURE_SCL=0"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="wsock32.lib"
|
||||
OutputFile="$(OutDir)/Common.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\Src\Common.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\CPUDetect.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\CPUDetect.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\DynamicLibrary.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\DynamicLibrary.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Hash.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Hash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HTTP.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HTTP.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\IniFile.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\IniFile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MappedFile.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MappedFile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MathUtil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MathUtil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MemArena.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MemArena.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MemoryUtil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\MemoryUtil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Plugin.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Plugin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PortableSockets.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PortableSockets.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="DebugFast|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="DebugFast|x64"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\StringUtil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\StringUtil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TestFramework.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
GeneratePreprocessedFile="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TestFramework.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Thread.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Thread.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Timer.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AssemblerOutput="2"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Timer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\x64Analyzer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\x64Analyzer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\x64Emitter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\x64Emitter.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
246
Source/Core/Common/Src/CPUDetect.cpp
Normal file
246
Source/Core/Common/Src/CPUDetect.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
//#include <config/i386/cpuid.h>
|
||||
#include <xmmintrin.h>
|
||||
void __cpuid(int info[4], int x) {}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "CPUDetect.h"
|
||||
|
||||
// This code was adapted from an example in MSDN:
|
||||
CPUInfoStruct cpu_info;
|
||||
|
||||
void CPUInfoStruct::Detect()
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
Mode64bit = false;
|
||||
#elif defined (_M_X64)
|
||||
Mode64bit = true;
|
||||
OS64bit = true;
|
||||
#endif
|
||||
numCores = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_IX86
|
||||
BOOL f64 = FALSE;
|
||||
OS64bit = IsWow64Process(GetCurrentProcess(), &f64) && f64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// __cpuid with an InfoType argument of 0 returns the number of
|
||||
// valid Ids in CPUInfo[0] and the CPU identification string in
|
||||
// the other three array elements. The CPU identification string is
|
||||
// not in linear order. The code below arranges the information
|
||||
// in a human readable form.
|
||||
__cpuid(CPUInfo, 0);
|
||||
nIds = CPUInfo[0];
|
||||
memset(CPUString, 0, sizeof(CPUString));
|
||||
*((int*)CPUString) = CPUInfo[1];
|
||||
*((int*)(CPUString + 4)) = CPUInfo[3];
|
||||
*((int*)(CPUString + 8)) = CPUInfo[2];
|
||||
|
||||
// Assume that everything non-intel is AMD
|
||||
if (memcmp(CPUString, "GenuineIntel", 12) == 0)
|
||||
{
|
||||
isAMD = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isAMD = true;
|
||||
}
|
||||
|
||||
// Get the information associated with each valid Id
|
||||
for (unsigned int i = 0; i <= nIds; ++i)
|
||||
{
|
||||
__cpuid(CPUInfo, i);
|
||||
|
||||
// Interpret CPU feature information.
|
||||
if (i == 1)
|
||||
{
|
||||
nSteppingID = CPUInfo[0] & 0xf;
|
||||
nModel = (CPUInfo[0] >> 4) & 0xf;
|
||||
nFamily = (CPUInfo[0] >> 8) & 0xf;
|
||||
nProcessorType = (CPUInfo[0] >> 12) & 0x3;
|
||||
nExtendedmodel = (CPUInfo[0] >> 16) & 0xf;
|
||||
nExtendedfamily = (CPUInfo[0] >> 20) & 0xff;
|
||||
nBrandIndex = CPUInfo[1] & 0xff;
|
||||
nCLFLUSHcachelinesize = ((CPUInfo[1] >> 8) & 0xff) * 8;
|
||||
nAPICPhysicalID = (CPUInfo[1] >> 24) & 0xff;
|
||||
bSSE3NewInstructions = (CPUInfo[2] & 0x1) || false;
|
||||
bMONITOR_MWAIT = (CPUInfo[2] & 0x8) || false;
|
||||
bCPLQualifiedDebugStore = (CPUInfo[2] & 0x10) || false;
|
||||
bThermalMonitor2 = (CPUInfo[2] & 0x100) || false;
|
||||
nFeatureInfo = CPUInfo[3];
|
||||
|
||||
if (CPUInfo[2] & (1 << 23))
|
||||
{
|
||||
bPOPCNT = true;
|
||||
}
|
||||
|
||||
if (CPUInfo[2] & (1 << 19))
|
||||
{
|
||||
bSSE4_1 = true;
|
||||
}
|
||||
|
||||
if (CPUInfo[2] & (1 << 20))
|
||||
{
|
||||
bSSE4_2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calling __cpuid with 0x80000000 as the InfoType argument
|
||||
// gets the number of valid extended IDs.
|
||||
__cpuid(CPUInfo, 0x80000000);
|
||||
nExIds = CPUInfo[0];
|
||||
memset(CPUBrandString, 0, sizeof(CPUBrandString));
|
||||
|
||||
// Get the information associated with each extended ID.
|
||||
for (unsigned int i = 0x80000000; i <= nExIds; ++i)
|
||||
{
|
||||
__cpuid(CPUInfo, i);
|
||||
|
||||
// Interpret CPU brand string and cache information.
|
||||
if (i == 0x80000001)
|
||||
{
|
||||
nFeatureInfo2 = CPUInfo[1]; // ECX
|
||||
bSSE5 = (nFeatureInfo2 & (1 << 11)) ? true : false;
|
||||
bLZCNT = (nFeatureInfo2 & (1 << 5)) ? true : false;
|
||||
bSSE4A = (nFeatureInfo2 & (1 << 6)) ? true : false;
|
||||
bLAHFSAHF64 = (nFeatureInfo2 & (1 << 0)) ? true : false;
|
||||
|
||||
CPU64bit = (CPUInfo[2] & (1 << 29)) ? true : false;
|
||||
}
|
||||
else if (i == 0x80000002)
|
||||
{
|
||||
memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
|
||||
}
|
||||
else if (i == 0x80000003)
|
||||
{
|
||||
memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
|
||||
}
|
||||
else if (i == 0x80000004)
|
||||
{
|
||||
memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
|
||||
}
|
||||
else if (i == 0x80000006)
|
||||
{
|
||||
nCacheLineSize = CPUInfo[2] & 0xff;
|
||||
nL2Associativity = (CPUInfo[2] >> 12) & 0xf;
|
||||
nCacheSizeK = (CPUInfo[2] >> 16) & 0xffff;
|
||||
}
|
||||
else if (i == 0x80000008)
|
||||
{
|
||||
int numLSB = (CPUInfo[2] >> 12) & 0xF;
|
||||
numCores = 1 << numLSB;
|
||||
//int coresPerDie = CPUInfo[2] & 0xFF;
|
||||
// numCores = coresPerDie;
|
||||
}
|
||||
}
|
||||
|
||||
// Display all the information in user-friendly format.
|
||||
// printf_s("\n\nCPU String: %s\n", CPUString);
|
||||
|
||||
if (nIds < 1)
|
||||
{
|
||||
bOldCPU = true;
|
||||
}
|
||||
|
||||
nIds = 1;
|
||||
bx87FPUOnChip = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bVirtual_8086ModeEnhancement = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bDebuggingExtensions = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bPageSizeExtensions = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bTimeStampCounter = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bRDMSRandWRMSRSupport = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bPhysicalAddressExtensions = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bMachineCheckException = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bCMPXCHG8BInstruction = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bAPICOnChip = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bUnknown1 = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bSYSENTERandSYSEXIT = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bMemoryTypeRangeRegisters = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bPTEGlobalBit = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bMachineCheckArchitecture = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bConditionalMove_CompareInstruction = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bPageAttributeTable = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bPageSizeExtension = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bProcessorSerialNumber = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bCFLUSHExtension = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bUnknown2 = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bDebugStore = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bThermalMonitorandClockCtrl = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bMMXTechnology = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bFXSAVE_FXRSTOR = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bSSEExtensions = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bSSE2Extensions = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bSelfSnoop = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bHyper_threadingTechnology = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bThermalMonitor = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bUnknown4 = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
bPendBrkEN = (nFeatureInfo & nIds) ? true : false;
|
||||
nIds <<= 1;
|
||||
|
||||
if (nExIds < 0x80000004)
|
||||
{
|
||||
strcpy(CPUBrandString, "(unknown)");
|
||||
}
|
||||
}
|
||||
|
||||
|
107
Source/Core/Common/Src/CPUDetect.h
Normal file
107
Source/Core/Common/Src/CPUDetect.h
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _CPUDETECT_H
|
||||
#define _CPUDETECT_H
|
||||
|
||||
struct CPUInfoStruct
|
||||
{
|
||||
bool isAMD;
|
||||
|
||||
bool OS64bit;
|
||||
bool CPU64bit;
|
||||
bool Mode64bit;
|
||||
int numCores;
|
||||
|
||||
char CPUString[0x20];
|
||||
char CPUBrandString[0x40];
|
||||
int CPUInfo[4];
|
||||
int nSteppingID;
|
||||
int nModel;
|
||||
int nFamily;
|
||||
int nProcessorType;
|
||||
int nExtendedmodel;
|
||||
int nExtendedfamily;
|
||||
int nBrandIndex;
|
||||
int nCLFLUSHcachelinesize;
|
||||
int nAPICPhysicalID;
|
||||
int nFeatureInfo;
|
||||
int nFeatureInfo2;
|
||||
int nCacheLineSize;
|
||||
int nL2Associativity;
|
||||
int nCacheSizeK;
|
||||
int nRet;
|
||||
unsigned int nIds, nExIds;
|
||||
|
||||
bool bMONITOR_MWAIT;
|
||||
bool bCPLQualifiedDebugStore;
|
||||
bool bThermalMonitor2;
|
||||
|
||||
bool bOldCPU;
|
||||
bool bx87FPUOnChip;
|
||||
bool bVirtual_8086ModeEnhancement;
|
||||
bool bDebuggingExtensions;
|
||||
bool bPageSizeExtensions;
|
||||
bool bTimeStampCounter;
|
||||
bool bRDMSRandWRMSRSupport;
|
||||
bool bPhysicalAddressExtensions;
|
||||
bool bMachineCheckException;
|
||||
bool bCMPXCHG8BInstruction;
|
||||
bool bAPICOnChip;
|
||||
bool bUnknown1;
|
||||
bool bSYSENTERandSYSEXIT;
|
||||
bool bMemoryTypeRangeRegisters;
|
||||
bool bPTEGlobalBit;
|
||||
bool bMachineCheckArchitecture;
|
||||
bool bConditionalMove_CompareInstruction;
|
||||
bool bPageAttributeTable;
|
||||
bool bPageSizeExtension;
|
||||
bool bProcessorSerialNumber;
|
||||
bool bCFLUSHExtension;
|
||||
bool bUnknown2;
|
||||
bool bDebugStore;
|
||||
bool bThermalMonitorandClockCtrl;
|
||||
bool bMMXTechnology;
|
||||
bool bFXSAVE_FXRSTOR;
|
||||
bool bSSEExtensions;
|
||||
bool bSSE2Extensions;
|
||||
bool bSSE3NewInstructions;
|
||||
bool bSelfSnoop;
|
||||
bool bHyper_threadingTechnology;
|
||||
bool bThermalMonitor;
|
||||
bool bUnknown4;
|
||||
bool bPendBrkEN;
|
||||
|
||||
bool bPOPCNT;
|
||||
bool bSSE4_1;
|
||||
bool bSSE4_2;
|
||||
bool bSSE5;
|
||||
bool bLZCNT;
|
||||
bool bSSE4A;
|
||||
bool bLAHFSAHF64;
|
||||
|
||||
void Detect();
|
||||
};
|
||||
|
||||
|
||||
extern CPUInfoStruct cpu_info;
|
||||
|
||||
inline void DetectCPU() {cpu_info.Detect();}
|
||||
|
||||
|
||||
#endif
|
||||
|
90
Source/Core/Common/Src/Common.cpp
Normal file
90
Source/Core/Common/Src/Common.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
PanicAlertHandler panic_handler = 0;
|
||||
}
|
||||
|
||||
void RegisterPanicAlertHandler(PanicAlertHandler handler)
|
||||
{
|
||||
panic_handler = handler;
|
||||
}
|
||||
|
||||
|
||||
void PanicAlert(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
if (panic_handler)
|
||||
{
|
||||
std::string msg;
|
||||
StringFromFormatV(&msg, format, args);
|
||||
panic_handler(msg.c_str(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string msg;
|
||||
StringFromFormatV(&msg, format, args);
|
||||
MessageBox(0, msg.c_str(), "PANIC!", MB_ICONWARNING);
|
||||
#elif __GNUC__
|
||||
//#error Do a messagebox!
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
bool PanicYesNo(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
bool retval;
|
||||
#ifdef _WIN32
|
||||
std::string msg;
|
||||
StringFromFormatV(&msg, format, args);
|
||||
retval = IDYES == MessageBox(0, msg.c_str(), "PANIC! Continue?", MB_ICONQUESTION | MB_YESNO);
|
||||
#elif __GNUC__
|
||||
//vprintf(format, args);
|
||||
return(true); //#error Do a messagebox!
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
// Standard implementation of logging - simply print to standard output.
|
||||
// Programs are welcome to override this.
|
||||
/*
|
||||
void __Log(int logNumber, const char *text, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
vprintf(text, args);
|
||||
va_end(args);
|
||||
}*/
|
306
Source/Core/Common/Src/Common.h
Normal file
306
Source/Core/Common/Src/Common.h
Normal file
@ -0,0 +1,306 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define POSIX 0
|
||||
#define NOMINMAX
|
||||
#define WEAK_SYMBOL __declspec(selectany)
|
||||
|
||||
#if _M_IX86
|
||||
#define Crash() {__asm int 3}
|
||||
#else
|
||||
#if _MSC_VER > 1000
|
||||
extern "C" {
|
||||
__declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
}
|
||||
#define Crash() {DebugBreak();}
|
||||
#else
|
||||
#error fixme
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif __GNUC__
|
||||
#define TCHAR char
|
||||
#define POSIX 1
|
||||
#define MAX_PATH 260
|
||||
#define WEAK_SYMBOL __attribute__((weak))
|
||||
#define stricmp strcasecmp
|
||||
#define Crash() {__builtin_trap();}
|
||||
// #ifdef 64bit
|
||||
// #define _M_IX86
|
||||
// #else
|
||||
#define _M_X64
|
||||
// #endf
|
||||
#endif
|
||||
|
||||
// Types
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
typedef unsigned __int64 u64;
|
||||
typedef unsigned __int32 u32;
|
||||
typedef unsigned __int16 u16;
|
||||
typedef unsigned __int8 u8;
|
||||
|
||||
typedef signed __int64 s64;
|
||||
typedef signed __int32 s32;
|
||||
typedef signed __int16 s16;
|
||||
typedef signed __int8 s8;
|
||||
|
||||
#define GC_ALIGNED16(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED16_DECL(x) __declspec(align(16)) x
|
||||
|
||||
#else
|
||||
|
||||
typedef char s8;
|
||||
typedef short s16;
|
||||
#define __int16 short
|
||||
typedef int s32;
|
||||
#define __int32 int
|
||||
typedef long long s64;
|
||||
#define __int64 long long
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned int BOOL;
|
||||
typedef unsigned int DWORD;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
#ifdef __LINUX__
|
||||
typedef union _LARGE_INTEGER
|
||||
{
|
||||
long long QuadPart;
|
||||
} LARGE_INTEGER;
|
||||
#endif
|
||||
|
||||
#if defined (__MINGW32__) || defined (_WIN32)
|
||||
#define GC_ALIGNED16(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED16_DECL(x) x
|
||||
#else
|
||||
#define GC_ALIGNED16(x) x
|
||||
#define GC_ALIGNED16_DECL(x) x __attribute((aligned(16)))
|
||||
#endif
|
||||
|
||||
#ifndef __forceinline
|
||||
#define __forceinline inline
|
||||
#endif
|
||||
|
||||
#ifndef _T
|
||||
#define _T(a) a
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined (_MSC_VER) && !defined (HAVE_ALIGNED_MALLOC)
|
||||
|
||||
// declare linux equivalents
|
||||
extern __forceinline void* gc_aligned_malloc(size_t size, size_t align)
|
||||
{
|
||||
char* p = (char*)malloc(size + align);
|
||||
int off = 2 + align - ((s64)(p + 2) % align);
|
||||
|
||||
p += off;
|
||||
*(u16*)(p - 2) = off;
|
||||
|
||||
return(p);
|
||||
}
|
||||
|
||||
|
||||
extern __forceinline void gc_aligned_free(void* pmem)
|
||||
{
|
||||
if (pmem != NULL)
|
||||
{
|
||||
char* p = (char*)pmem;
|
||||
free(p - (int)*(u16*)(p - 2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define _aligned_malloc gc_aligned_malloc
|
||||
#define _aligned_free gc_aligned_free
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (_M_IX86) && defined (_WIN32)
|
||||
#define HWCALL __cdecl
|
||||
#else
|
||||
#define HWCALL
|
||||
#endif
|
||||
|
||||
|
||||
// Hacks
|
||||
#ifndef SAFE_DELETE
|
||||
#define SAFE_DELETE(ptr) if (ptr){delete ptr; ptr = 0;}
|
||||
#endif
|
||||
|
||||
// Common defines
|
||||
// TODO(ector,fires): turn into inline function?
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
template<class T>
|
||||
T min(const T& a, const T& b) {return(a > b ? b : a);}
|
||||
|
||||
|
||||
template<class T>
|
||||
T max(const T& a, const T& b) {return(a > b ? a : b);}
|
||||
|
||||
|
||||
|
||||
|
||||
// Byte ordering
|
||||
|
||||
namespace Common
|
||||
{
|
||||
inline u8 swap8(u8 _data) {return(_data);}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
inline u16 swap16(u16 _data) {return(_byteswap_ushort(_data));}
|
||||
|
||||
|
||||
inline u32 swap32(u32 _data) {return(_byteswap_ulong(_data));}
|
||||
|
||||
|
||||
inline u64 swap64(u64 _data) {return(_byteswap_uint64(_data));}
|
||||
|
||||
|
||||
#elif __linux__
|
||||
}
|
||||
#include <byteswap.h>
|
||||
namespace Common
|
||||
{
|
||||
inline u16 swap16(u16 _data) {return(bswap_16(_data));}
|
||||
|
||||
|
||||
inline u32 swap32(u32 _data) {return(bswap_32(_data));}
|
||||
|
||||
|
||||
inline u64 swap64(u64 _data) {return(bswap_64(_data));}
|
||||
|
||||
|
||||
#else
|
||||
inline u16 swap16(u16 data) {return((data >> 8) | (data << 8));}
|
||||
|
||||
|
||||
inline u32 swap32(u32 data) {return((swap16(data) << 16) | swap16(data >> 16));}
|
||||
|
||||
|
||||
inline u64 swap64(u64 data) {return(((u64)swap32(data) << 32) | swap32(data >> 32));}
|
||||
#endif
|
||||
|
||||
|
||||
} // end of namespace Common
|
||||
|
||||
// Utility functions
|
||||
|
||||
void PanicAlert(const char* text, ...);
|
||||
bool PanicYesNo(const char* text, ...);
|
||||
extern void __Log(int logNumber, const char* text, ...);
|
||||
|
||||
|
||||
// dummy class
|
||||
class LogTypes
|
||||
{
|
||||
public:
|
||||
|
||||
enum LOG_TYPE
|
||||
{
|
||||
MASTER_LOG,
|
||||
BOOT,
|
||||
PIXELENGINE,
|
||||
COMMANDPROCESSOR,
|
||||
VIDEOINTERFACE,
|
||||
SERIALINTERFACE,
|
||||
PERIPHERALINTERFACE,
|
||||
MEMMAP,
|
||||
DSPINTERFACE,
|
||||
STREAMINGINTERFACE,
|
||||
DVDINTERFACE,
|
||||
GPFIFO,
|
||||
EXPANSIONINTERFACE,
|
||||
AUDIO_INTERFACE,
|
||||
GEKKO,
|
||||
HLE,
|
||||
DSPHLE,
|
||||
VIDEO,
|
||||
AUDIO,
|
||||
DYNA_REC,
|
||||
OSREPORT,
|
||||
CONSOLE,
|
||||
WII_IOB,
|
||||
WII_IPC,
|
||||
WII_IPC_HLE,
|
||||
NUMBER_OF_LOGS
|
||||
};
|
||||
};
|
||||
|
||||
typedef bool (*PanicAlertHandler)(const char* text, bool yes_no);
|
||||
void RegisterPanicAlertHandler(PanicAlertHandler handler);
|
||||
|
||||
void Host_UpdateLogDisplay();
|
||||
|
||||
|
||||
// Logging macros
|
||||
#ifdef LOGGING
|
||||
|
||||
#define LOG(t, ...) __Log(LogTypes::t, __VA_ARGS__);
|
||||
|
||||
#define _dbg_assert_(_t_, _a_) \
|
||||
if (!(_a_)){\
|
||||
LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \
|
||||
__LINE__, __FILE__, __TIME__); \
|
||||
if (!PanicYesNo("*** Assertion (see log)***\n")){Crash();} \
|
||||
}
|
||||
#define _dbg_assert_msg_(_t_, _a_, ...)\
|
||||
if (!(_a_)){\
|
||||
LOG(_t_, __VA_ARGS__); \
|
||||
if (!PanicYesNo(__VA_ARGS__)){Crash();} \
|
||||
}
|
||||
#define _dbg_update_() Host_UpdateLogDisplay();
|
||||
|
||||
#else
|
||||
|
||||
#define LOG(_t_, ...)
|
||||
#define _dbg_clear_()
|
||||
#define _dbg_assert_(_t_, _a_) ;
|
||||
#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) ;
|
||||
#define _dbg_update_() ;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_)
|
||||
#define _assert_msg_(_t_, _a_, _fmt_, ...)\
|
||||
if (!(_a_)){\
|
||||
if (!PanicYesNo(_fmt_, __VA_ARGS__)){Crash();} \
|
||||
}
|
||||
#else
|
||||
#define _assert_(a)
|
||||
#define _assert_msg_(...)
|
||||
#endif
|
||||
#endif
|
109
Source/Core/Common/Src/DynamicLibrary.cpp
Normal file
109
Source/Core/Common/Src/DynamicLibrary.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "DynamicLibrary.h"
|
||||
|
||||
DynamicLibrary::DynamicLibrary()
|
||||
{
|
||||
library = 0;
|
||||
}
|
||||
|
||||
|
||||
bool DynamicLibrary::Load(const char* filename)
|
||||
{
|
||||
if (strlen(filename) == 0)
|
||||
{
|
||||
PanicAlert("DynamicLibrary : Missing filename");
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (IsLoaded())
|
||||
{
|
||||
PanicAlert("Trying to load already loaded library %s", filename);
|
||||
return(false);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
library = LoadLibrary(filename);
|
||||
#else
|
||||
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
|
||||
|
||||
if (!library)
|
||||
{
|
||||
PanicAlert(dlerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Successfully loaded %s", filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
return(library != 0);
|
||||
}
|
||||
|
||||
|
||||
void DynamicLibrary::Unload()
|
||||
{
|
||||
if (!IsLoaded())
|
||||
{
|
||||
PanicAlert("Trying to unload non-loaded library");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FreeLibrary(library);
|
||||
#else
|
||||
dlclose(library);
|
||||
#endif
|
||||
library = 0;
|
||||
}
|
||||
|
||||
|
||||
void* DynamicLibrary::Get(const char* funcname) const
|
||||
{
|
||||
void* retval;
|
||||
#ifdef _WIN32
|
||||
retval = GetProcAddress(library, funcname);
|
||||
|
||||
if (!retval)
|
||||
{
|
||||
// PanicAlert("Did not find function %s in DLL", funcname);
|
||||
}
|
||||
|
||||
return(retval);
|
||||
|
||||
#else
|
||||
retval = dlsym(library, funcname);
|
||||
|
||||
if (!retval)
|
||||
{
|
||||
printf("%s\n", dlerror());
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
46
Source/Core/Common/Src/DynamicLibrary.h
Normal file
46
Source/Core/Common/Src/DynamicLibrary.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _DYNAMICLIBRARY_H
|
||||
#define _DYNAMICLIBRARY_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
class DynamicLibrary
|
||||
{
|
||||
public:
|
||||
|
||||
DynamicLibrary();
|
||||
bool Load(const char* filename);
|
||||
void Unload();
|
||||
void* Get(const char* funcname) const;
|
||||
|
||||
|
||||
bool IsLoaded() const {return(library != 0);}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
HINSTANCE library;
|
||||
#else
|
||||
void* library;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
309
Source/Core/Common/Src/HTTP.cpp
Normal file
309
Source/Core/Common/Src/HTTP.cpp
Normal file
@ -0,0 +1,309 @@
|
||||
// Under MIT licence from http://www.mindcontrol.org/~hplus/http-get.html
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "HTTP.h"
|
||||
#include "PortableSockets.h"
|
||||
|
||||
#if !defined(WIN32)
|
||||
static int strnicmp( char const * a, char const * b, int n) {
|
||||
return strncasecmp( a, b, n );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct Chunk {
|
||||
Chunk() {
|
||||
next_ = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
Chunk * next_;
|
||||
size_t size_;
|
||||
char data_[ 30000 ];
|
||||
};
|
||||
|
||||
class HTTPQuery : public I_HTTPRequest {
|
||||
public:
|
||||
HTTPQuery() {
|
||||
head_ = 0;
|
||||
curRd_ = 0;
|
||||
curWr_ = 0;
|
||||
curOffset_ = 0;
|
||||
toRead_ = 0;
|
||||
complete_ = false;
|
||||
gotLength_ = false;
|
||||
socket_ = BAD_SOCKET_FD;
|
||||
}
|
||||
~HTTPQuery() {
|
||||
if (socket_ != BAD_SOCKET_FD) {
|
||||
::closesocket( socket_ );
|
||||
}
|
||||
Chunk * ch = head_;
|
||||
while( ch != 0) {
|
||||
Chunk * d = ch;
|
||||
ch = ch->next_;
|
||||
::free( d );
|
||||
}
|
||||
}
|
||||
|
||||
void setQuery( char const * host, unsigned short port, char const * url) {
|
||||
if (strlen( url ) > 1536 || strlen( host ) > 256) {
|
||||
return;
|
||||
}
|
||||
struct hostent * hent = gethostbyname( host );
|
||||
if (hent == 0) {
|
||||
complete_ = true;
|
||||
return;
|
||||
}
|
||||
addr_.sin_family = AF_INET;
|
||||
addr_.sin_addr = *(in_addr *)hent->h_addr_list[0];
|
||||
addr_.sin_port = htons( port );
|
||||
socket_ = ::socket( AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto );
|
||||
if (socket_ == BAD_SOCKET_FD) {
|
||||
complete_ = true;
|
||||
return;
|
||||
}
|
||||
int r;
|
||||
r = ::connect( socket_, (sockaddr *)&addr_, sizeof( addr_ ) );
|
||||
if (r < 0) {
|
||||
complete_ = true;
|
||||
return;
|
||||
}
|
||||
MAKE_SOCKET_NONBLOCKING( socket_, r );
|
||||
if (r < 0) {
|
||||
complete_ = true;
|
||||
return;
|
||||
}
|
||||
char buf[2048];
|
||||
sprintf( buf, "GET %s HTTP/1.0\r\nUser-Agent: Dolphin2.0\r\nAccept: */*\r\nHost: %s\r\nConnection: close\r\n\r\n",
|
||||
url, host );
|
||||
r = ::send( socket_, buf, int(strlen( buf )), NONBLOCK_MSG_SEND );
|
||||
if (r != (int)strlen( buf )) {
|
||||
complete_ = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
delete this;
|
||||
}
|
||||
void step() {
|
||||
if (!complete_) {
|
||||
if (!curWr_ || (curWr_->size_ == sizeof( curWr_->data_ ))) {
|
||||
Chunk * c = new Chunk;
|
||||
if (!head_) {
|
||||
head_ = c;
|
||||
curWr_ = c;
|
||||
}
|
||||
else {
|
||||
curWr_->next_ = c;
|
||||
curWr_ = c;
|
||||
}
|
||||
}
|
||||
assert( curWr_ && (curWr_->size_ < sizeof( curWr_->data_ )) );
|
||||
int r = ::recv( socket_, &curWr_->data_[curWr_->size_], int(sizeof(curWr_->data_)-curWr_->size_),
|
||||
NONBLOCK_MSG_SEND );
|
||||
if (r > 0) {
|
||||
curWr_->size_ += r;
|
||||
assert( curWr_->size_ <= sizeof( curWr_->data_ ) );
|
||||
if (gotLength_) {
|
||||
if (toRead_ <= size_t(r)) {
|
||||
toRead_ = 0;
|
||||
complete_ = true;
|
||||
}
|
||||
else {
|
||||
toRead_ -= r;
|
||||
}
|
||||
}
|
||||
if (!gotLength_) {
|
||||
char const * end = &head_->data_[head_->size_];
|
||||
char const * ptr = &head_->data_[1];
|
||||
while( ptr < end-1) {
|
||||
if (ptr[-1] == '\n') {
|
||||
if (!strnicmp( ptr, "content-length:", 15 )) {
|
||||
ptr += 15;
|
||||
toRead_ = strtol( ptr, (char **)&ptr, 10 );
|
||||
gotLength_ = true;
|
||||
}
|
||||
else if (ptr[0] == '\r' && ptr[1] == '\n') {
|
||||
size_t haveRead = end-ptr-2;
|
||||
if (haveRead > toRead_) {
|
||||
toRead_ = 0;
|
||||
}
|
||||
else {
|
||||
toRead_ -= haveRead;
|
||||
}
|
||||
if (toRead_ == 0) {
|
||||
complete_ = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (r < 0) {
|
||||
if (!SOCKET_WOULDBLOCK_ERROR( SOCKET_ERRNO )) {
|
||||
complete_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool complete() {
|
||||
step();
|
||||
return complete_;
|
||||
}
|
||||
void rewind() {
|
||||
curRd_ = head_;
|
||||
curOffset_ = 0;
|
||||
}
|
||||
size_t read( void * ptr, size_t size) {
|
||||
step();
|
||||
if (!head_) {
|
||||
return 0;
|
||||
}
|
||||
if (!curRd_) {
|
||||
curRd_ = head_;
|
||||
assert( curOffset_ == 0 );
|
||||
}
|
||||
size_t copied = 0;
|
||||
while( size > 0) {
|
||||
assert( curRd_->size_ <= sizeof( curRd_->data_ ) );
|
||||
size_t toCopy = curRd_->size_ - curOffset_;
|
||||
if (toCopy > size) {
|
||||
toCopy = size;
|
||||
}
|
||||
memcpy( ptr, &curRd_->data_[curOffset_], toCopy );
|
||||
curOffset_ += toCopy;
|
||||
assert( curOffset_ <= sizeof(curRd_->data_) );
|
||||
ptr = ((char *)ptr)+toCopy;
|
||||
size -= toCopy;
|
||||
copied += toCopy;
|
||||
if (curOffset_ == curRd_->size_) {
|
||||
if (curRd_->next_ != 0) {
|
||||
curRd_ = curRd_->next_;
|
||||
curOffset_ = 0;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
Chunk * head_;
|
||||
Chunk * curRd_;
|
||||
Chunk * curWr_;
|
||||
size_t curOffset_;
|
||||
size_t toRead_;
|
||||
bool complete_;
|
||||
bool gotLength_;
|
||||
SOCKET socket_;
|
||||
sockaddr_in addr_;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
I_HTTPRequest * NewHTTPRequest( char const * url )
|
||||
{
|
||||
static bool socketsInited;
|
||||
if (!socketsInited) {
|
||||
socketsInited = true;
|
||||
INIT_SOCKET_LIBRARY();
|
||||
}
|
||||
if (strncmp( url, "http://", 7 )) {
|
||||
return 0;
|
||||
}
|
||||
url += 7;
|
||||
char const * path = strchr( url, '/' );
|
||||
if (!path) {
|
||||
return 0;
|
||||
}
|
||||
char name[ 256 ];
|
||||
if (path-url > 255) {
|
||||
return 0;
|
||||
}
|
||||
strncpy( name, url, path-url );
|
||||
name[path-url] = 0;
|
||||
char * port = strrchr( name, ':' );
|
||||
unsigned short iport = 80;
|
||||
if (port) {
|
||||
*port = 0;
|
||||
iport = (unsigned short)( strtol( port+1, &port, 10 ) );
|
||||
}
|
||||
HTTPQuery * q = new HTTPQuery;
|
||||
q->setQuery( name, iport, path );
|
||||
return q;
|
||||
}
|
||||
|
||||
// TODO(ector):
|
||||
// Currently extremely bad implementation - busy waits!
|
||||
std::string HTTPDownloadText(const char *url)
|
||||
{
|
||||
I_HTTPRequest *r = NewHTTPRequest(url);
|
||||
int timeout = 10;
|
||||
std::string text = "";
|
||||
time_t t;
|
||||
t = 0;
|
||||
char buf[4096];
|
||||
while (true)
|
||||
{
|
||||
r->step();
|
||||
size_t rd = r->read(buf, 4096);
|
||||
if (rd > 0)
|
||||
{
|
||||
buf[rd] = 0;
|
||||
text += buf;
|
||||
}
|
||||
else {
|
||||
if (r->complete())
|
||||
goto next;
|
||||
|
||||
if (!t) {
|
||||
time(&t);
|
||||
}
|
||||
else {
|
||||
time_t t2;
|
||||
time(&t2);
|
||||
if (t2 > t + timeout) {
|
||||
fprintf( stderr, "timeout\n");
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
next:
|
||||
r->dispose();
|
||||
return text;
|
||||
}
|
||||
|
||||
void UnittestMyNetwork()
|
||||
{
|
||||
I_HTTPRequest * r = NewHTTPRequest( "http://www.cisco.com/" );
|
||||
char buf[1024];
|
||||
while( !r->complete()) {
|
||||
r->step();
|
||||
while( r->read( buf, sizeof( buf ) ) )
|
||||
;
|
||||
}
|
||||
char buf2[100000];
|
||||
r->rewind();
|
||||
while( r->read( buf2, sizeof( buf2 ) ) )
|
||||
;
|
||||
r->dispose();
|
||||
}
|
34
Source/Core/Common/Src/HTTP.h
Normal file
34
Source/Core/Common/Src/HTTP.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Under MIT licence from http://www.mindcontrol.org/~hplus/http-get.html
|
||||
|
||||
#if !defined( mynetwork_h )
|
||||
#define mynetwork_h
|
||||
|
||||
#include <string>
|
||||
|
||||
// I_HTTPRequest will run until it's received all available data
|
||||
// from the query. You can rewind and read the data received just
|
||||
// like a regular stream. Reading will return 0 bytes when at the
|
||||
// end, even if the query isn't yet complete. Test for completeness
|
||||
// with complete(). You need to step() the query every so often to
|
||||
// retrieve more data. Calling complete() and rewind() may step
|
||||
// the query.
|
||||
class I_HTTPRequest {
|
||||
public:
|
||||
virtual ~I_HTTPRequest() {}
|
||||
virtual void dispose() = 0;
|
||||
virtual void step() = 0;
|
||||
virtual bool complete() = 0;
|
||||
virtual void rewind() = 0;
|
||||
virtual size_t read(void * ptr, size_t data) = 0;
|
||||
};
|
||||
|
||||
// The format of "url" is "http://host:port/path". Name resolution
|
||||
// will be done synchronously, which can be a problem.
|
||||
// This request will NOT deal with user names and passwords. You
|
||||
// have been warned!
|
||||
I_HTTPRequest * NewHTTPRequest(char const * url);
|
||||
|
||||
std::string HTTPDownloadText(const char *url);
|
||||
|
||||
#endif
|
||||
|
138
Source/Core/Common/Src/Hash.cpp
Normal file
138
Source/Core/Common/Src/Hash.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Hash.h"
|
||||
|
||||
// uint32_t
|
||||
// WARNING - may read one more byte!
|
||||
// Implementation from Wikipedia.
|
||||
u32 HashFletcher(const u8* data_u8, size_t length)
|
||||
{
|
||||
const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */
|
||||
size_t len = (length + 1) / 2; /* Length in 16-bit words */
|
||||
u32 sum1 = 0xffff, sum2 = 0xffff;
|
||||
|
||||
while (len)
|
||||
{
|
||||
size_t tlen = len > 360 ? 360 : len;
|
||||
len -= tlen;
|
||||
|
||||
do {
|
||||
sum1 += *data++;
|
||||
sum2 += sum1;
|
||||
}
|
||||
while (--tlen);
|
||||
|
||||
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
||||
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
||||
}
|
||||
|
||||
/* Second reduction step to reduce sums to 16 bits */
|
||||
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
|
||||
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
|
||||
return(sum2 << 16 | sum1);
|
||||
}
|
||||
|
||||
|
||||
// Implementation from Wikipedia
|
||||
// Slightly slower than Fletcher above, but slighly more reliable.
|
||||
#define MOD_ADLER 65521
|
||||
// data: Pointer to the data to be summed; len is in bytes
|
||||
u32 HashAdler32(const u8* data, size_t len)
|
||||
{
|
||||
u32 a = 1, b = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
size_t tlen = len > 5550 ? 5550 : len;
|
||||
len -= tlen;
|
||||
|
||||
do
|
||||
{
|
||||
a += *data++;
|
||||
b += a;
|
||||
}
|
||||
while (--tlen);
|
||||
|
||||
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
|
||||
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
||||
}
|
||||
|
||||
// It can be shown that a <= 0x1013a here, so a single subtract will do.
|
||||
if (a >= MOD_ADLER)
|
||||
{
|
||||
a -= MOD_ADLER;
|
||||
}
|
||||
|
||||
// It can be shown that b can reach 0xfff87 here.
|
||||
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
|
||||
|
||||
if (b >= MOD_ADLER)
|
||||
{
|
||||
b -= MOD_ADLER;
|
||||
}
|
||||
|
||||
return((b << 16) | a);
|
||||
}
|
||||
|
||||
|
||||
// Another fast and decent hash
|
||||
u32 HashFNV(const u8* ptr, int length)
|
||||
{
|
||||
u32 hash = 0x811c9dc5;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
hash *= 1677761;
|
||||
hash ^= ptr[i];
|
||||
}
|
||||
|
||||
return(hash);
|
||||
}
|
||||
|
||||
|
||||
// Another fast and decent hash
|
||||
u32 HashFNV1(const u8* ptr, int length)
|
||||
{
|
||||
u32 hash = 0x811c9dc5;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
hash *= 1677761;
|
||||
hash ^= ptr[i];
|
||||
}
|
||||
|
||||
return(hash);
|
||||
}
|
||||
|
||||
|
||||
// Terribly stupid hash - but can't go back now :)
|
||||
// Don't use for new things. At least it's fast.
|
||||
u32 HashEctor(const u8* ptr, int length)
|
||||
{
|
||||
u32 crc = 0;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
crc ^= ptr[i];
|
||||
crc = (crc << 3) | (crc >> 29);
|
||||
}
|
||||
|
||||
return(crc);
|
||||
}
|
||||
|
||||
|
28
Source/Core/Common/Src/Hash.h
Normal file
28
Source/Core/Common/Src/Hash.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _HASH_H
|
||||
#define _HASH_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
u32 HashFletcher(const u8* data_u8, size_t length); // FAST
|
||||
u32 HashAdler32(const u8* data, size_t len); // Fairly accurate, slightly slower
|
||||
u32 HashFNV(const u8* ptr, int length); // Another fast and decent hash
|
||||
u32 HashEctor(const u8* ptr, int length); // JUNK. DO NOT USE FOR NEW THINGS
|
||||
|
||||
|
||||
#endif
|
464
Source/Core/Common/Src/IniFile.cpp
Normal file
464
Source/Core/Common/Src/IniFile.cpp
Normal file
@ -0,0 +1,464 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// see IniFile.h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "StringUtil.h"
|
||||
#include "IniFile.h"
|
||||
|
||||
IniFile::IniFile()
|
||||
{}
|
||||
|
||||
|
||||
IniFile::~IniFile()
|
||||
{}
|
||||
|
||||
|
||||
Section::Section()
|
||||
: name(""), comment(""), lines() {}
|
||||
|
||||
|
||||
Section::Section(const std::string& _name)
|
||||
: name(_name), comment(""), lines() {}
|
||||
|
||||
|
||||
Section::Section(const Section& other)
|
||||
{
|
||||
name = other.name;
|
||||
comment = other.comment;
|
||||
lines = other.lines;
|
||||
}
|
||||
|
||||
|
||||
Section* IniFile::GetSection(const char* sectionName)
|
||||
{
|
||||
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||
{
|
||||
if (!strcmp(iter->name.c_str(), sectionName))
|
||||
{
|
||||
return(&(*iter));
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
Section* IniFile::GetOrCreateSection(const char* sectionName)
|
||||
{
|
||||
Section* section = GetSection(sectionName);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
sections.push_back(Section(sectionName));
|
||||
section = §ions[sections.size() - 1];
|
||||
}
|
||||
|
||||
return(section);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::DeleteSection(const char* sectionName)
|
||||
{
|
||||
Section* s = GetSection(sectionName);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
for (std::vector<Section>::iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||
{
|
||||
if (&(*iter) == s)
|
||||
{
|
||||
sections.erase(iter);
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut)
|
||||
{
|
||||
// allow many types of commenting
|
||||
// These MUST be signed! Do not change to size_t
|
||||
int firstEquals = (int)line.find("=", 0);
|
||||
int firstCommentChar = (int)line.find(";", 0);
|
||||
|
||||
if (firstCommentChar < 0){firstCommentChar = (int)line.find("#", firstEquals > 0 ? firstEquals : 0);}
|
||||
|
||||
if (firstCommentChar < 0){firstCommentChar = (int)line.find("//", firstEquals > 0 ? firstEquals : 0);}
|
||||
|
||||
// allow preserval of spacing before comment
|
||||
if (firstCommentChar > 0)
|
||||
{
|
||||
while (line[firstCommentChar - 1] == ' ' || line[firstCommentChar - 1] == 9) // 9 == tab
|
||||
{
|
||||
firstCommentChar--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((firstEquals >= 0) && ((firstCommentChar < 0) || (firstEquals < firstCommentChar)))
|
||||
{
|
||||
// Yes, a valid line!
|
||||
*keyOut = StripSpaces(line.substr(0, firstEquals));
|
||||
|
||||
if (commentOut)
|
||||
{
|
||||
*commentOut = firstCommentChar > 0 ? line.substr(firstCommentChar) : std::string("");
|
||||
}
|
||||
|
||||
if (valueOut)
|
||||
{
|
||||
*valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, firstCommentChar - firstEquals - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string* IniFile::GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut)
|
||||
{
|
||||
for (std::vector<std::string>::iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
||||
{
|
||||
std::string& line = *iter;
|
||||
std::string lineKey;
|
||||
ParseLine(line, &lineKey, valueOut, commentOut);
|
||||
|
||||
if (!stricmp(lineKey.c_str(), key))
|
||||
{
|
||||
return(&line);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void IniFile::Set(const char* sectionName, const char* key, const char* newValue)
|
||||
{
|
||||
Section* section = GetOrCreateSection(sectionName);
|
||||
std::string value, comment;
|
||||
std::string* line = GetLine(section, key, &value, &comment);
|
||||
|
||||
if (line)
|
||||
{
|
||||
// Change the value - keep the key and comment
|
||||
*line = StripSpaces(key) + " = " + newValue + comment;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The key did not already exist in this section - let's add it.
|
||||
section->lines.push_back(std::string(key) + " = " + newValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IniFile::Set(const char* sectionName, const char* key, u32 newValue)
|
||||
{
|
||||
Set(sectionName, key, StringFromFormat("0x%08x", newValue).c_str());
|
||||
}
|
||||
|
||||
|
||||
void IniFile::Set(const char* sectionName, const char* key, int newValue)
|
||||
{
|
||||
Set(sectionName, key, StringFromInt(newValue).c_str());
|
||||
}
|
||||
|
||||
|
||||
void IniFile::Set(const char* sectionName, const char* key, bool newValue)
|
||||
{
|
||||
Set(sectionName, key, StringFromBool(newValue).c_str());
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue)
|
||||
{
|
||||
Section* section = GetSection(sectionName);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
if (defaultValue)
|
||||
{
|
||||
*value = defaultValue;
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
std::string* line = GetLine(section, key, value, 0);
|
||||
|
||||
if (!line)
|
||||
{
|
||||
if (defaultValue)
|
||||
{
|
||||
*value = defaultValue;
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::Get(const char* sectionName, const char* key, int* value, int defaultValue)
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(sectionName, key, &temp, 0);
|
||||
|
||||
if (retval && TryParseInt(temp.c_str(), value))
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
*value = defaultValue;
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::Get(const char* sectionName, const char* key, u32* value, u32 defaultValue)
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(sectionName, key, &temp, 0);
|
||||
|
||||
if (retval && TryParseUInt(temp.c_str(), value))
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
*value = defaultValue;
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue)
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(sectionName, key, &temp, 0);
|
||||
|
||||
if (retval && TryParseBool(temp.c_str(), value))
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
*value = defaultValue;
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::DeleteKey(const char* sectionName, const char* key)
|
||||
{
|
||||
Section* section = GetSection(sectionName);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
std::string* line = GetLine(section, key, 0, 0);
|
||||
|
||||
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
||||
{
|
||||
if (line == &(*liter))
|
||||
{
|
||||
section->lines.erase(liter);
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(false); //shouldn't happen
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::Load(const char* filename)
|
||||
{
|
||||
sections.clear();
|
||||
sections.push_back(Section(""));
|
||||
//first section consists of the comments before the first real section
|
||||
|
||||
std::ifstream in;
|
||||
in.open(filename, std::ios::in);
|
||||
|
||||
if (in.fail())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
while (!in.eof())
|
||||
{
|
||||
char templine[512];
|
||||
in.getline(templine, 512);
|
||||
std::string line = templine;
|
||||
|
||||
if (in.eof())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.size() > 0)
|
||||
{
|
||||
if (line[0] == '[')
|
||||
{
|
||||
int endpos = (int)line.find("]");
|
||||
|
||||
if (endpos != std::string::npos)
|
||||
{
|
||||
// New section!
|
||||
std::string sub = line.substr(1, endpos - 1);
|
||||
sections.push_back(Section(sub));
|
||||
|
||||
if (endpos + 1 < line.size())
|
||||
{
|
||||
sections[sections.size() - 1].comment = line.substr(endpos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sections[sections.size() - 1].lines.push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in.close();
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::Save(const char* filename)
|
||||
{
|
||||
std::ofstream out;
|
||||
out.open(filename, std::ios::out);
|
||||
|
||||
if (out.fail())
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||
{
|
||||
const Section& section = *iter;
|
||||
|
||||
if (section.name != "")
|
||||
{
|
||||
out << "[" << section.name << "]" << section.comment << std::endl;
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
|
||||
{
|
||||
std::string s = *liter;
|
||||
out << s << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
out.close();
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys)
|
||||
{
|
||||
Section* section = GetSection(sectionName);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
keys.clear();
|
||||
|
||||
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
||||
{
|
||||
std::string key;
|
||||
ParseLine(*liter, &key, 0, 0);
|
||||
keys.push_back(key);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines)
|
||||
{
|
||||
Section* section = GetSection(sectionName);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
lines.clear();
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
|
||||
{
|
||||
std::string line = StripSpaces(*iter);
|
||||
int commentPos = (int)line.find('#');
|
||||
|
||||
if (commentPos == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (commentPos != (int)std::string::npos)
|
||||
{
|
||||
line = StripSpaces(line.substr(0, commentPos));
|
||||
}
|
||||
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
lines = section->lines;
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
void IniFile::SortSections()
|
||||
{
|
||||
std::sort(sections.begin(), sections.end());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
int main()
|
||||
{
|
||||
IniFile ini;
|
||||
ini.Load("my.ini");
|
||||
ini.Set("Hej", "A", "amaskdfl");
|
||||
ini.Set("Mossa", "A", "amaskdfl");
|
||||
ini.Set("Aissa", "A", "amaskdfl");
|
||||
//ini.Read("my.ini");
|
||||
std::string x;
|
||||
ini.Get("Hej", "B", &x, "boo");
|
||||
ini.DeleteKey("Mossa", "A");
|
||||
ini.DeleteSection("Mossa");
|
||||
ini.SortSections();
|
||||
ini.Save("my.ini");
|
||||
//UpdateVars(ini);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
92
Source/Core/Common/Src/IniFile.h
Normal file
92
Source/Core/Common/Src/IniFile.h
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _INIFILE_H
|
||||
#define _INIFILE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
class Section
|
||||
{
|
||||
public:
|
||||
|
||||
Section();
|
||||
Section(const std::string& _name);
|
||||
Section(const Section& other);
|
||||
std::vector<std::string>lines;
|
||||
std::string name;
|
||||
std::string comment;
|
||||
|
||||
bool operator<(const Section& other) const
|
||||
{
|
||||
return(name < other.name);
|
||||
}
|
||||
};
|
||||
|
||||
class IniFile
|
||||
{
|
||||
public:
|
||||
|
||||
IniFile();
|
||||
~IniFile();
|
||||
|
||||
bool Load(const char* filename);
|
||||
bool Save(const char* filename);
|
||||
|
||||
void Set(const char* sectionName, const char* key, const char* newValue);
|
||||
void Set(const char* sectionName, const char* key, int newValue);
|
||||
void Set(const char* sectionName, const char* key, u32 newValue);
|
||||
void Set(const char* sectionName, const char* key, bool newValue);
|
||||
|
||||
|
||||
void Set(const char* sectionName, const char* key, const std::string& newValue) {Set(sectionName, key, newValue.c_str());}
|
||||
|
||||
|
||||
void Set(const char* sectionName, const char* key, const std::vector<std::string>& newValues);
|
||||
|
||||
bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = "");
|
||||
bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0);
|
||||
bool Get(const char* sectionName, const char* key, u32* value, u32 defaultValue = 0);
|
||||
bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false);
|
||||
bool Get(const char* sectionName, const char* key, std::vector<std::string>& values);
|
||||
|
||||
bool GetKeys(const char* sectionName, std::vector<std::string>& keys);
|
||||
bool GetLines(const char* sectionName, std::vector<std::string>& lines);
|
||||
|
||||
bool DeleteKey(const char* sectionName, const char* key);
|
||||
bool DeleteSection(const char* sectionName);
|
||||
|
||||
void SortSections();
|
||||
|
||||
void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut);
|
||||
std::string* GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Section>sections;
|
||||
|
||||
Section* GetSection(const char* section);
|
||||
Section* GetOrCreateSection(const char* section);
|
||||
std::string* GetLine(const char* section, const char* key);
|
||||
void CreateSection(const char* section);
|
||||
};
|
||||
|
||||
#endif
|
95
Source/Core/Common/Src/Logging.cpp
Normal file
95
Source/Core/Common/Src/Logging.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#if 0
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// constructor
|
||||
//
|
||||
CDebugger_Log::CDebugger_Log(const char* _szShortName, const char* _szName)
|
||||
: m_pFile(NULL),
|
||||
m_bLogToFile(false),
|
||||
m_bShowInLog(false),
|
||||
m_bEnable(false)
|
||||
{
|
||||
strcpy((char*)m_szName, _szName);
|
||||
strcpy((char*)m_szShortName, _szShortName);
|
||||
sprintf((char*)m_szFilename, "logs\\%s.txt", _szShortName);
|
||||
|
||||
_unlink(m_szFilename);
|
||||
}
|
||||
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// destructor
|
||||
//
|
||||
CDebugger_Log::~CDebugger_Log(void)
|
||||
{
|
||||
if (m_pFile)
|
||||
{
|
||||
fclose(m_pFile);
|
||||
m_pFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CDebugger_Log::LoadSettings(IniFile& ini)
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp, "%s_LogToFile", m_szShortName);
|
||||
ini.Get("Logging", temp, &m_bLogToFile, false);
|
||||
|
||||
sprintf(temp, "%s_ShowInLog", m_szShortName);
|
||||
ini.Get("Logging", temp, &m_bShowInLog, true);
|
||||
|
||||
sprintf(temp, "%s_Enable", m_szShortName);
|
||||
ini.Get("Logging", temp, &m_bEnable, true);
|
||||
}
|
||||
|
||||
|
||||
void CDebugger_Log::SaveSettings(IniFile& ini)
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp, "%s_LogToFile", m_szShortName);
|
||||
ini.Set("Logging", temp, m_bLogToFile);
|
||||
sprintf(temp, "%s_ShowInLog", m_szShortName);
|
||||
ini.Set("Logging", temp, m_bShowInLog);
|
||||
sprintf(temp, "%s_Enable", m_szShortName);
|
||||
ini.Set("Logging", temp, m_bEnable);
|
||||
}
|
||||
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Init
|
||||
//
|
||||
void
|
||||
CDebugger_Log::Init(void)
|
||||
{
|
||||
if (m_pFile != NULL)
|
||||
{
|
||||
fclose(m_pFile);
|
||||
m_pFile = NULL;
|
||||
}
|
||||
|
||||
// reopen the file and rewrite it
|
||||
m_pFile = fopen(m_szFilename, "wt");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
92
Source/Core/Common/Src/Logging.h
Normal file
92
Source/Core/Common/Src/Logging.h
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#if 0
|
||||
|
||||
// THESE WILL BE REPLACED WITH A CLEANED UP LOGGING SYSTEM
|
||||
|
||||
#ifndef _LOGGING_H
|
||||
#define _LOGGING_H
|
||||
|
||||
class IniFile;
|
||||
|
||||
// should be inside the LogManager ...
|
||||
struct CDebugger_Log
|
||||
{
|
||||
char m_szName[128];
|
||||
char m_szShortName[10];
|
||||
char m_szFilename[256];
|
||||
bool m_bLogToFile;
|
||||
bool m_bShowInLog;
|
||||
bool m_bEnable;
|
||||
FILE* m_pFile;
|
||||
|
||||
void Init(void);
|
||||
|
||||
|
||||
// constructor
|
||||
CDebugger_Log(const char* _szShortName, const char* _szName);
|
||||
|
||||
// destructor
|
||||
~CDebugger_Log(void);
|
||||
};
|
||||
|
||||
|
||||
#ifdef LOGGING
|
||||
|
||||
#define LOG(_t_, ...) LogManager::Log(LogManager::_t_, __VA_ARGS__);
|
||||
|
||||
#define _dbg_assert_(_t_, _a_)\
|
||||
if (!(_a_)){\
|
||||
char szError[512]; \
|
||||
sprintf_s(szError, 512, "Error localized at...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", __LINE__, __FILE__, __TIMESTAMP__); \
|
||||
LOG(_t_, szError); \
|
||||
if (MessageBox(NULL, szError, "*** Assertion Report ***", MB_YESNO | MB_ICONERROR) == IDNO){Crash();} \
|
||||
}
|
||||
#define _dbg_assert_msg_(_t_, _a_, _fmt_, ...)\
|
||||
if (!(_a_)){\
|
||||
char szError[582], szError2[512]; \
|
||||
sprintf_s(szError2, 512, _fmt_, __VA_ARGS__); \
|
||||
sprintf_s(szError, 582, "Desc.: %s\n\nIgnore and continue?", szError2); \
|
||||
LOG(_t_, szError); \
|
||||
if (MessageBox(NULL, szError, "*** Fatal Error ***", MB_YESNO | MB_ICONERROR) == IDNO){Crash();} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define LOG(_t_, ...)
|
||||
#define _dbg_clear_()
|
||||
#define _dbg_assert_(_t_, _a_) ;
|
||||
#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) ;
|
||||
#define _dbg_update_() ;
|
||||
|
||||
#endif
|
||||
|
||||
#define _assert_msg_(_t_, _a_, _fmt_, ...)\
|
||||
if (!(_a_)){\
|
||||
char szError[582], szError2[512]; \
|
||||
sprintf_s(szError2, 512, _fmt_, __VA_ARGS__); \
|
||||
sprintf_s(szError, 582, "Desc.: %s\n\nIgnore and continue?", szError2); \
|
||||
LOG(_t_, szError); \
|
||||
if (MessageBox(NULL, szError, "*** Fatal Error ***", MB_YESNO | MB_ICONERROR) == IDNO){Crash();} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
232
Source/Core/Common/Src/MappedFile.cpp
Normal file
232
Source/Core/Common/Src/MappedFile.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "MappedFile.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class CMappedFile
|
||||
: public IMappedFile
|
||||
{
|
||||
public:
|
||||
|
||||
CMappedFile(void);
|
||||
~CMappedFile(void);
|
||||
bool Open(const char* _szFilename);
|
||||
bool IsOpen(void);
|
||||
void Close(void);
|
||||
u64 GetSize(void);
|
||||
u8* Lock(u64 _offset, u64 _size);
|
||||
void Unlock(u8* ptr);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
u64 size;
|
||||
|
||||
typedef std::map<u8*, u8*>Lockmap;
|
||||
Lockmap lockMap;
|
||||
#ifdef _WIN32
|
||||
HANDLE hFile;
|
||||
HANDLE hFileMapping;
|
||||
#elif POSIX
|
||||
int fd;
|
||||
typedef std::map<u8*, size_t>Sizemap;
|
||||
Sizemap sizeMap;
|
||||
#endif
|
||||
|
||||
int granularity;
|
||||
};
|
||||
|
||||
|
||||
CMappedFile::CMappedFile()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
granularity = (int)info.dwAllocationGranularity;
|
||||
#elif POSIX
|
||||
fd = -1;
|
||||
granularity = getpagesize(); //sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CMappedFile::~CMappedFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
bool CMappedFile::Open(const char* filename)
|
||||
{
|
||||
Close();
|
||||
#ifdef _WIN32
|
||||
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
hFileMapping = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);
|
||||
|
||||
if (hFileMapping == NULL)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
hFile = 0;
|
||||
return(false);
|
||||
}
|
||||
|
||||
u32 high = 0;
|
||||
u32 low = GetFileSize(hFile, (LPDWORD)&high);
|
||||
size = (u64)low | ((u64)high << 32);
|
||||
#elif POSIX
|
||||
fd = open(filename, O_RDONLY);
|
||||
size = 0; //TODO
|
||||
#endif
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool CMappedFile::IsOpen()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return(hFile != INVALID_HANDLE_VALUE);
|
||||
|
||||
#elif POSIX
|
||||
return(fd != -1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
u64 CMappedFile::GetSize()
|
||||
{
|
||||
return(size);
|
||||
}
|
||||
|
||||
|
||||
void CMappedFile::Close()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hFileMapping);
|
||||
CloseHandle(hFile);
|
||||
lockMap.clear();
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
#elif POSIX
|
||||
if (fd != -1)
|
||||
{
|
||||
lockMap.clear();
|
||||
sizeMap.clear();
|
||||
close(fd);
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
u8* CMappedFile::Lock(u64 offset, u64 size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
#elif POSIX
|
||||
if (fd != -1)
|
||||
#endif
|
||||
{
|
||||
u64 realOffset = offset & ~(granularity - 1);
|
||||
s64 difference = offset - realOffset;
|
||||
u64 fake_size = ((offset & 4095) + size + 4095) & 4095;
|
||||
#ifdef _WIN32
|
||||
u8* realPtr = (u8*)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD)(realOffset >> 32), (DWORD)realOffset, (SIZE_T)(size));
|
||||
|
||||
if (realPtr == NULL)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
#elif POSIX
|
||||
// TODO
|
||||
u8* realPtr = (u8*)mmap(0, fake_size, PROT_READ, MAP_PRIVATE, fd, (off_t)realOffset);
|
||||
|
||||
if (!realPtr)
|
||||
{
|
||||
PanicAlert("Map Failed");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
u8* fakePtr = realPtr + difference;
|
||||
//add to map
|
||||
lockMap[fakePtr] = realPtr;
|
||||
#ifndef _WIN32
|
||||
sizeMap[fakePtr] = size + difference;
|
||||
#endif
|
||||
return(fakePtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMappedFile::Unlock(u8* ptr)
|
||||
{
|
||||
if (ptr != 0)
|
||||
{
|
||||
Lockmap::iterator iter = lockMap.find(ptr);
|
||||
|
||||
if (iter != lockMap.end())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UnmapViewOfFile((*iter).second);
|
||||
#else
|
||||
munmap((*iter).second, sizeMap[ptr]);
|
||||
#endif
|
||||
lockMap.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("CMappedFile : Unlock failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IMappedFile* IMappedFile::CreateMappedFile(void)
|
||||
{
|
||||
return(new CMappedFile);
|
||||
}
|
||||
} // end of namespace Common
|
51
Source/Core/Common/Src/MappedFile.h
Normal file
51
Source/Core/Common/Src/MappedFile.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Handles giant memory mapped files
|
||||
// Through some trickery, allows lock on byte boundaries
|
||||
// instead of allocation granularity boundaries
|
||||
// for ease of use
|
||||
//
|
||||
|
||||
#ifndef _MAPPED_FILE_H
|
||||
#define _MAPPED_FILE_H
|
||||
|
||||
// #pragma warning (disable: 4786)
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class IMappedFile
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~IMappedFile() {}
|
||||
|
||||
|
||||
virtual bool Open(const char* _szFilename) = 0;
|
||||
virtual bool IsOpen(void) = 0;
|
||||
virtual void Close(void) = 0;
|
||||
virtual u64 GetSize(void) = 0;
|
||||
virtual u8* Lock(u64 _offset, u64 _size) = 0;
|
||||
virtual void Unlock(u8* ptr) = 0;
|
||||
|
||||
static IMappedFile* CreateMappedFile();
|
||||
};
|
||||
} // end of namespace DiscIO
|
||||
|
||||
#endif
|
||||
|
44
Source/Core/Common/Src/MathUtil.cpp
Normal file
44
Source/Core/Common/Src/MathUtil.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
static u32 saved_sse_state = _mm_getcsr();
|
||||
static const u32 default_sse_state = _mm_getcsr();
|
||||
|
||||
|
||||
void LoadDefaultSSEState()
|
||||
{
|
||||
_mm_setcsr(default_sse_state);
|
||||
}
|
||||
|
||||
|
||||
void LoadSSEState()
|
||||
{
|
||||
_mm_setcsr(saved_sse_state);
|
||||
}
|
||||
|
||||
|
||||
void SaveSSEState()
|
||||
{
|
||||
saved_sse_state = _mm_getcsr();
|
||||
}
|
||||
|
||||
|
35
Source/Core/Common/Src/MathUtil.h
Normal file
35
Source/Core/Common/Src/MathUtil.h
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _MATH_UTIL_H
|
||||
#define _MATH_UTIL_H
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
/*
|
||||
There are two different flavors of float to int conversion:
|
||||
_mm_cvtps_epi32() and _mm_cvttps_epi32(). The first rounds
|
||||
according to the MXCSR rounding bits. The second one always
|
||||
uses round towards zero.
|
||||
*/
|
||||
|
||||
void SaveSSEState();
|
||||
void LoadSSEState();
|
||||
void LoadDefaultSSEState();
|
||||
|
||||
|
||||
#endif
|
126
Source/Core/Common/Src/MemArena.cpp
Normal file
126
Source/Core/Common/Src/MemArena.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemArena.h"
|
||||
|
||||
|
||||
const char* ram_temp_file = "/tmp/gc_mem.tmp";
|
||||
|
||||
void MemArena::GrabLowMemSpace(size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
hMemoryMapping = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, (DWORD)(size), _T("All GC Memory"));
|
||||
#else
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
|
||||
ftruncate(fd, size);
|
||||
return;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MemArena::ReleaseSpace()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(hMemoryMapping);
|
||||
hMemoryMapping = 0;
|
||||
#else
|
||||
close(fd);
|
||||
unlink(ram_temp_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return(MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size));
|
||||
|
||||
#else
|
||||
void* ptr = mmap(0, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | (ensure_low_mem ? MAP_32BIT : 0),
|
||||
fd, offset);
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
PanicAlert("Failed to create view");
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void* MemArena::CreateViewAt(s64 offset, size_t size, void* base)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return(MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base));
|
||||
|
||||
#else
|
||||
return(mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, offset));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MemArena::ReleaseView(void* view, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UnmapViewOfFile(view);
|
||||
#else
|
||||
munmap(view, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
u64 MemArena::Find4GBBase()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
#ifdef _WIN32
|
||||
u8* base = (u8*)VirtualAlloc(0, 0x100000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
return((u64)base);
|
||||
|
||||
#else
|
||||
// Very precarious - mmap cannot return an error when trying to map already used pages.
|
||||
// This makes the Windows approach above unusable on Linux, so we will simply pray...
|
||||
return(0x2300000000ULL);
|
||||
#endif
|
||||
|
||||
#else
|
||||
// Only grab a bit less than 1GB
|
||||
u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
return((u64)base);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
56
Source/Core/Common/Src/MemArena.h
Normal file
56
Source/Core/Common/Src/MemArena.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _MEMARENA_H
|
||||
#define _MEMARENA_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it.
|
||||
// Multiple views can mirror the same section of the block, which makes it very convient for emulating
|
||||
// memory mirrors.
|
||||
// Pass ensure_low_mem = true to CreateView if you want arbitrarily positioned views to end up in the low 2GB.
|
||||
|
||||
class MemArena
|
||||
{
|
||||
public:
|
||||
|
||||
void GrabLowMemSpace(size_t size);
|
||||
void ReleaseSpace();
|
||||
void* CreateView(s64 offset, size_t size, bool ensure_low_mem = false);
|
||||
void* CreateViewAt(s64 offset, size_t size, void* base);
|
||||
void ReleaseView(void* view, size_t size);
|
||||
|
||||
|
||||
// This only finds 1 GB in 32-bit
|
||||
static u64 Find4GBBase();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hMemoryMapping;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
123
Source/Core/Common/Src/MemoryUtil.cpp
Normal file
123
Source/Core/Common/Src/MemoryUtil.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif __GNUC__
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
// MacOSX does not support MAP_VARIABLE
|
||||
#ifndef MAP_VARIABLE
|
||||
#define MAP_VARIABLE 0
|
||||
#endif
|
||||
|
||||
// This is purposedely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
|
||||
void* AllocateExecutableMemory(int size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
if ((u64)ptr >= 0x80000000)
|
||||
{
|
||||
PanicAlert("Executable memory ended up above 2GB! WTF!");
|
||||
// If this happens, we have to implement a free ram search scheme. ector knows how.
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
|
||||
#else
|
||||
void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // | MAP_FIXED
|
||||
printf("mappah exe %p %i\n", retval, size);
|
||||
|
||||
if (!retval)
|
||||
{
|
||||
PanicAlert("Failed to allocate executable memory, errno=%i", errno);
|
||||
}
|
||||
|
||||
return(retval);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void* AllocateMemoryPages(int size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
PanicAlert("Failed to allocate raw memory");
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
|
||||
#else
|
||||
void* retval = mmap(0, size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // | MAP_FIXED
|
||||
printf("mappah %p %i\n", retval, size);
|
||||
|
||||
if (!retval)
|
||||
{
|
||||
PanicAlert("Failed to allocate raw memory, errno=%i", errno);
|
||||
}
|
||||
|
||||
return(retval);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FreeMemoryPages(void* ptr, int size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualFree(ptr, size, MEM_RELEASE);
|
||||
#else
|
||||
munmap(ptr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void WriteProtectMemory(void* ptr, int size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, 0);
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void UnWriteProtectMemory(void* ptr, int size, bool allowExecute)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READONLY, 0);
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
31
Source/Core/Common/Src/MemoryUtil.h
Normal file
31
Source/Core/Common/Src/MemoryUtil.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _MEMORYUTIL_H
|
||||
#define _MEMORYUTIL_H
|
||||
|
||||
void* AllocateExecutableMemory(int size);
|
||||
void* AllocateMemoryPages(int size);
|
||||
void FreeMemoryPages(void* ptr, int size);
|
||||
void WriteProtectMemory(void* ptr, int size, bool executable = false);
|
||||
void UnWriteProtectMemory(void* ptr, int size, bool allowExecute);
|
||||
|
||||
|
||||
inline int GetPageSize() {return(4096);}
|
||||
|
||||
|
||||
#endif
|
80
Source/Core/Common/Src/Plugin.cpp
Normal file
80
Source/Core/Common/Src/Plugin.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
DynamicLibrary CPlugin::m_hInstLib;
|
||||
|
||||
void(__cdecl * CPlugin::m_GetDllInfo) (PLUGIN_INFO * _PluginInfo) = 0;
|
||||
void(__cdecl * CPlugin::m_DllAbout) (HWND _hParent) = 0;
|
||||
void(__cdecl * CPlugin::m_DllConfig) (HWND _hParent) = 0;
|
||||
|
||||
void
|
||||
CPlugin::Release(void)
|
||||
{
|
||||
m_GetDllInfo = 0;
|
||||
m_DllAbout = 0;
|
||||
m_DllConfig = 0;
|
||||
|
||||
m_hInstLib.Unload();
|
||||
}
|
||||
|
||||
bool
|
||||
CPlugin::Load(const char* _szName)
|
||||
{
|
||||
if (m_hInstLib.Load(_szName))
|
||||
{
|
||||
m_GetDllInfo = (void (__cdecl*)(PLUGIN_INFO*))m_hInstLib.Get("GetDllInfo");
|
||||
m_DllAbout = (void (__cdecl*)(HWND))m_hInstLib.Get("DllAbout");
|
||||
m_DllConfig = (void (__cdecl*)(HWND))m_hInstLib.Get("DllConfig");
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
bool CPlugin::GetInfo(PLUGIN_INFO& _pluginInfo)
|
||||
{
|
||||
if (m_GetDllInfo != 0)
|
||||
{
|
||||
m_GetDllInfo(&_pluginInfo);
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
void CPlugin::Config(HWND _hwnd)
|
||||
{
|
||||
if (m_DllConfig != 0)
|
||||
{
|
||||
m_DllConfig(_hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
void CPlugin::About(HWND _hwnd)
|
||||
{
|
||||
if (m_DllAbout != 0)
|
||||
{
|
||||
m_DllAbout(_hwnd);
|
||||
}
|
||||
}
|
||||
} // end of namespace Common
|
50
Source/Core/Common/Src/Plugin.h
Normal file
50
Source/Core/Common/Src/Plugin.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _PLUGIN_H
|
||||
#define _PLUGIN_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "../../../PluginSpecs/PluginSpecs.h"
|
||||
#include "DynamicLibrary.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class CPlugin
|
||||
{
|
||||
public:
|
||||
|
||||
static void Release(void);
|
||||
static bool Load(const char* _szName);
|
||||
|
||||
static bool GetInfo(PLUGIN_INFO& _pluginInfo);
|
||||
|
||||
static void Config(HWND _hwnd);
|
||||
static void About(HWND _hwnd);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
static DynamicLibrary m_hInstLib;
|
||||
|
||||
static void (__cdecl * m_GetDllInfo)(PLUGIN_INFO* _PluginInfo);
|
||||
static void (__cdecl * m_DllAbout)(HWND _hParent);
|
||||
static void (__cdecl * m_DllConfig)(HWND _hParent);
|
||||
};
|
||||
} // end of namespace Common
|
||||
|
||||
#endif
|
550
Source/Core/Common/Src/PortableSockets.cpp
Normal file
550
Source/Core/Common/Src/PortableSockets.cpp
Normal file
@ -0,0 +1,550 @@
|
||||
// Under MIT licence from http://www.mindcontrol.org/~hplus/http-get.html
|
||||
|
||||
#include "PortableSockets.h"
|
||||
|
||||
#if NEED_GETTIMEOFDAY
|
||||
#if defined( _WIN32 )
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#pragma comment( lib, "winmm.lib" )
|
||||
//#pragma comment( lib, "ws2_32.lib" )
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// This class could be made cheaper using RDTSC for short-term
|
||||
// measurement. But, whatever.
|
||||
class init_gettimeofday
|
||||
{
|
||||
public:
|
||||
init_gettimeofday()
|
||||
{
|
||||
timeBeginPeriod( 2 );
|
||||
__int64 rr;
|
||||
QueryPerformanceFrequency( (LARGE_INTEGER *)&rr );
|
||||
ticksPerSecInv_ = 1.0 / (double)((DWORD)rr & 0xffffffff);
|
||||
int watchdog = 0;
|
||||
again:
|
||||
lastTicks_ = timeGetTime();
|
||||
QueryPerformanceCounter( (LARGE_INTEGER *)&lastRead_ );
|
||||
timeb tb;
|
||||
ftime( &tb );
|
||||
timeOffset_ = tb.time + tb.millitm * 0.001 - lastRead_ * ticksPerSecInv_;
|
||||
lastTime_ = timeOffset_;
|
||||
// make sure it didn't take too long
|
||||
if( watchdog++ < 10 && (timeGetTime() != lastTicks_) ) {
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
~init_gettimeofday()
|
||||
{
|
||||
timeEndPeriod( 2 );
|
||||
}
|
||||
|
||||
void get( timeval * tv )
|
||||
{
|
||||
__int64 nu;
|
||||
int watchdog = 0;
|
||||
again:
|
||||
DWORD m = timeGetTime();
|
||||
QueryPerformanceCounter( (LARGE_INTEGER *)&nu );
|
||||
DWORD n = timeGetTime();
|
||||
// guard against pre-emption
|
||||
if( (watchdog++ < 10) && (n != m) ) {
|
||||
goto again;
|
||||
}
|
||||
double nuTime = nu * ticksPerSecInv_ + timeOffset_;
|
||||
if( (nu - lastRead_) & 0x7fffffff80000000ULL ) {
|
||||
// there's a chance that we're seeing a jump-ahead
|
||||
double adjust = (nuTime - lastTime_ - (n - lastTicks_) * 0.001);
|
||||
if( adjust > 0.1f ) {
|
||||
timeOffset_ -= adjust;
|
||||
nuTime -= adjust;
|
||||
assert( nuTime >= lastTime_ );
|
||||
}
|
||||
}
|
||||
lastRead_ = nu;
|
||||
lastTicks_ = n;
|
||||
lastTime_ = nuTime;
|
||||
tv->tv_sec = (ulong)floor( nuTime );
|
||||
tv->tv_usec = (ulong)(1000000 * (nuTime - tv->tv_sec));
|
||||
}
|
||||
|
||||
double ticksPerSecInv_;
|
||||
double timeOffset_;
|
||||
double lastTime_;
|
||||
__int64 lastRead_;
|
||||
DWORD lastTicks_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void gettimeofday( timeval * tv, int )
|
||||
{
|
||||
static init_gettimeofday data;
|
||||
data.get( tv );
|
||||
}
|
||||
|
||||
#else
|
||||
#error "don't know how to do this"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if NEED_WINDOWS_POLL
|
||||
#if defined( WIN32 )
|
||||
|
||||
#include <assert.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
// This is somewhat less than ideal -- better would be if we could
|
||||
// abstract pollfd enough that it's non-copying on Windows.
|
||||
int poll( pollfd * iofds, size_t count, int ms )
|
||||
{
|
||||
FD_SET rd, wr, ex;
|
||||
FD_ZERO( &rd );
|
||||
FD_ZERO( &wr );
|
||||
FD_ZERO( &ex );
|
||||
SOCKET m = 0;
|
||||
for( size_t ix = 0; ix < count; ++ix ) {
|
||||
iofds[ix].revents = 0;
|
||||
if( iofds[ix].fd >= m ) {
|
||||
m = iofds[ix].fd + 1;
|
||||
}
|
||||
if( iofds[ix].events & (POLLIN | POLLPRI) ) {
|
||||
assert( rd.fd_count < FD_SETSIZE );
|
||||
rd.fd_array[ rd.fd_count++ ] = iofds[ix].fd;
|
||||
}
|
||||
if( iofds[ix].events & (POLLOUT) ) {
|
||||
assert( wr.fd_count < FD_SETSIZE );
|
||||
wr.fd_array[ wr.fd_count++ ] = iofds[ix].fd;
|
||||
}
|
||||
assert( ex.fd_count < FD_SETSIZE );
|
||||
ex.fd_array[ ex.fd_count++ ] = iofds[ix].fd;
|
||||
}
|
||||
timeval tv;
|
||||
tv.tv_sec = ms/1000;
|
||||
tv.tv_usec = (ms - (tv.tv_sec * 1000)) * 1000;
|
||||
int r = 0;
|
||||
if( m == 0 ) {
|
||||
::Sleep( ms );
|
||||
}
|
||||
else {
|
||||
r = ::select( (int)m, (rd.fd_count ? &rd : 0), (wr.fd_count ? &wr : 0), (ex.fd_count ? &ex : 0), &tv );
|
||||
}
|
||||
if( r < 0 ) {
|
||||
int err = WSAGetLastError();
|
||||
errno = err;
|
||||
return r;
|
||||
}
|
||||
r = 0;
|
||||
for( size_t ix = 0; ix < count; ++ix ) {
|
||||
for( size_t iy = 0; iy < rd.fd_count; ++iy ) {
|
||||
if( rd.fd_array[ iy ] == iofds[ix].fd ) {
|
||||
iofds[ix].revents |= POLLIN;
|
||||
++r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for( size_t iy = 0; iy < wr.fd_count; ++iy ) {
|
||||
if( wr.fd_array[ iy ] == iofds[ix].fd ) {
|
||||
iofds[ix].revents |= POLLOUT;
|
||||
++r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for( size_t iy = 0; iy < ex.fd_count; ++iy ) {
|
||||
if( ex.fd_array[ iy ] == iofds[ix].fd ) {
|
||||
iofds[ix].revents |= POLLERR;
|
||||
++r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "don't know how to do this"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if NEED_FIREWALL_ENABLE
|
||||
#if defined( WIN32 )
|
||||
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x500
|
||||
|
||||
#include <objbase.h>
|
||||
#include <oleauto.h>
|
||||
//#include <netfw.h>
|
||||
|
||||
/*
|
||||
#define _ASSERT assert
|
||||
|
||||
namespace {
|
||||
|
||||
HRESULT WindowsFirewallInitialize(OUT INetFwProfile** fwProfile)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
INetFwMgr* fwMgr = NULL;
|
||||
INetFwPolicy* fwPolicy = NULL;
|
||||
|
||||
_ASSERT(fwProfile != NULL);
|
||||
|
||||
*fwProfile = NULL;
|
||||
|
||||
// Create an instance of the firewall settings manager.
|
||||
hr = CoCreateInstance(
|
||||
__uuidof(NetFwMgr),
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
__uuidof(INetFwMgr),
|
||||
(void**)&fwMgr
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("CoCreateInstance failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Retrieve the local firewall policy.
|
||||
hr = fwMgr->get_LocalPolicy(&fwPolicy);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("get_LocalPolicy failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Retrieve the firewall profile currently in effect.
|
||||
hr = fwPolicy->get_CurrentProfile(fwProfile);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("get_CurrentProfile failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
// Release the local firewall policy.
|
||||
if (fwPolicy != NULL)
|
||||
{
|
||||
fwPolicy->Release();
|
||||
}
|
||||
|
||||
// Release the firewall settings manager.
|
||||
if (fwMgr != NULL)
|
||||
{
|
||||
fwMgr->Release();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void WindowsFirewallCleanup(IN INetFwProfile* fwProfile)
|
||||
{
|
||||
// Release the firewall profile.
|
||||
if (fwProfile != NULL)
|
||||
{
|
||||
fwProfile->Release();
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT WindowsFirewallAppIsEnabled(
|
||||
IN INetFwProfile* fwProfile,
|
||||
IN const wchar_t* fwProcessImageFileName,
|
||||
OUT BOOL* fwAppEnabled
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BSTR fwBstrProcessImageFileName = NULL;
|
||||
VARIANT_BOOL fwEnabled;
|
||||
INetFwAuthorizedApplication* fwApp = NULL;
|
||||
INetFwAuthorizedApplications* fwApps = NULL;
|
||||
|
||||
_ASSERT(fwProfile != NULL);
|
||||
_ASSERT(fwProcessImageFileName != NULL);
|
||||
_ASSERT(fwAppEnabled != NULL);
|
||||
|
||||
*fwAppEnabled = FALSE;
|
||||
|
||||
// Retrieve the authorized application collection.
|
||||
hr = fwProfile->get_AuthorizedApplications(&fwApps);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("get_AuthorizedApplications failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Allocate a BSTR for the process image file name.
|
||||
fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
|
||||
if (SysStringLen(fwBstrProcessImageFileName) == 0)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
printf("SysAllocString failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Attempt to retrieve the authorized application.
|
||||
hr = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Find out if the authorized application is enabled.
|
||||
hr = fwApp->get_Enabled(&fwEnabled);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("get_Enabled failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fwEnabled != VARIANT_FALSE)
|
||||
{
|
||||
// The authorized application is enabled.
|
||||
*fwAppEnabled = TRUE;
|
||||
|
||||
printf(
|
||||
"Authorized application %lS is enabled in the firewall.\n",
|
||||
fwProcessImageFileName
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(
|
||||
"Authorized application %lS is disabled in the firewall.\n",
|
||||
fwProcessImageFileName
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The authorized application was not in the collection.
|
||||
hr = S_OK;
|
||||
|
||||
printf(
|
||||
"Authorized application %lS is disabled in the firewall.\n",
|
||||
fwProcessImageFileName
|
||||
);
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
// Free the BSTR.
|
||||
SysFreeString(fwBstrProcessImageFileName);
|
||||
|
||||
// Release the authorized application instance.
|
||||
if (fwApp != NULL)
|
||||
{
|
||||
fwApp->Release();
|
||||
}
|
||||
|
||||
// Release the authorized application collection.
|
||||
if (fwApps != NULL)
|
||||
{
|
||||
fwApps->Release();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT WindowsFirewallAddApp(
|
||||
IN INetFwProfile* fwProfile,
|
||||
IN const wchar_t* fwProcessImageFileName,
|
||||
IN const wchar_t* fwName
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fwAppEnabled;
|
||||
BSTR fwBstrName = NULL;
|
||||
BSTR fwBstrProcessImageFileName = NULL;
|
||||
INetFwAuthorizedApplication* fwApp = NULL;
|
||||
INetFwAuthorizedApplications* fwApps = NULL;
|
||||
|
||||
_ASSERT(fwProfile != NULL);
|
||||
_ASSERT(fwProcessImageFileName != NULL);
|
||||
_ASSERT(fwName != NULL);
|
||||
|
||||
// First check to see if the application is already authorized.
|
||||
hr = WindowsFirewallAppIsEnabled(
|
||||
fwProfile,
|
||||
fwProcessImageFileName,
|
||||
&fwAppEnabled
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("WindowsFirewallAppIsEnabled failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Only add the application if it isn't already authorized.
|
||||
if (!fwAppEnabled)
|
||||
{
|
||||
// Retrieve the authorized application collection.
|
||||
hr = fwProfile->get_AuthorizedApplications(&fwApps);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("get_AuthorizedApplications failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Create an instance of an authorized application.
|
||||
hr = CoCreateInstance(
|
||||
__uuidof(NetFwAuthorizedApplication),
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
__uuidof(INetFwAuthorizedApplication),
|
||||
(void**)&fwApp
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("CoCreateInstance failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Allocate a BSTR for the process image file name.
|
||||
fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
|
||||
if (SysStringLen(fwBstrProcessImageFileName) == 0)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
printf("SysAllocString failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Set the process image file name.
|
||||
hr = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("put_ProcessImageFileName failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Allocate a BSTR for the application friendly name.
|
||||
fwBstrName = SysAllocString(fwName);
|
||||
if (SysStringLen(fwBstrName) == 0)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
printf("SysAllocString failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Set the application friendly name.
|
||||
hr = fwApp->put_Name(fwBstrName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("put_Name failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Add the application to the collection.
|
||||
hr = fwApps->Add(fwApp);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
printf("Add failed: 0x%08lx\n", hr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
printf(
|
||||
"Authorized application %lS is now enabled in the firewall.\n",
|
||||
fwProcessImageFileName
|
||||
);
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
// Free the BSTRs.
|
||||
SysFreeString(fwBstrName);
|
||||
SysFreeString(fwBstrProcessImageFileName);
|
||||
|
||||
// Release the authorized application instance.
|
||||
if (fwApp != NULL)
|
||||
{
|
||||
fwApp->Release();
|
||||
}
|
||||
|
||||
// Release the authorized application collection.
|
||||
if (fwApps != NULL)
|
||||
{
|
||||
fwApps->Release();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ENABLE_FIREWALL()
|
||||
{
|
||||
BOOL couldEnable = false;
|
||||
HRESULT hr = S_OK;
|
||||
HRESULT comInit = E_FAIL;
|
||||
INetFwProfile* fwProfile = NULL;
|
||||
|
||||
// Initialize COM.
|
||||
#if 1
|
||||
comInit = CoInitialize( 0 );
|
||||
#else
|
||||
comInit = CoInitializeEx(
|
||||
0,
|
||||
COINIT_APARTMENTTHREADED //| COINIT_DISABLE_OLE1DDE
|
||||
);
|
||||
#endif
|
||||
|
||||
// Ignore RPC_E_CHANGED_MODE; this just means that COM has already been
|
||||
// initialized with a different mode. Since we don't care what the mode is,
|
||||
// we'll just use the existing mode.
|
||||
if (comInit != RPC_E_CHANGED_MODE) {
|
||||
hr = comInit;
|
||||
if (FAILED(hr)) {
|
||||
fprintf( stderr, "CoInitializeEx failed: 0x%08lx\n", hr );
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the firewall profile currently in effect.
|
||||
hr = WindowsFirewallInitialize(&fwProfile);
|
||||
if (FAILED(hr)) {
|
||||
fprintf( stderr, "WindowsFirewallInitialize failed: 0x%08lx\n", hr );
|
||||
goto error;
|
||||
}
|
||||
|
||||
HMODULE hm = GetModuleHandle( 0 );
|
||||
wchar_t path[512];
|
||||
if( !GetModuleFileNameW( hm, path, sizeof(path)/sizeof(wchar_t) ) ) {
|
||||
fprintf( stderr, "GetModuleFileName() failed: 0x%lx\n", GetLastError() );
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Add the application to the authorized application collection.
|
||||
hr = WindowsFirewallAddApp(
|
||||
fwProfile,
|
||||
path,
|
||||
L"Introduction Library User"
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
fprintf( stderr, "WindowsFirewallAddApp failed: 0x%08lx\n", hr );
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
WindowsFirewallCleanup(fwProfile);
|
||||
|
||||
if (SUCCEEDED(comInit)) {
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
return couldEnable != FALSE;
|
||||
}
|
||||
*/
|
||||
|
||||
#else
|
||||
#error "don't know how to do this"
|
||||
#endif
|
||||
|
||||
#endif
|
189
Source/Core/Common/Src/PortableSockets.h
Normal file
189
Source/Core/Common/Src/PortableSockets.h
Normal file
@ -0,0 +1,189 @@
|
||||
// Under MIT licence from http://www.mindcontrol.org/~hplus/http-get.html
|
||||
|
||||
#if !defined( sock_port_h )
|
||||
#define sock_port_h
|
||||
|
||||
// There are differences between Linux/Berkeley sockets and WinSock2
|
||||
// This file wraps some of the more common ones (as used by this library).
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined( WIN32 )
|
||||
|
||||
// Windows features go here
|
||||
#include <Winsock2.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined( NEED_SHORT_TYPES )
|
||||
#define NEED_SHORT_TYPES 1
|
||||
#endif
|
||||
#if !defined( NEED_WINDOWS_POLL )
|
||||
#define NEED_WINDOWS_POLL 1
|
||||
#endif
|
||||
#if !defined( NEED_GETTIMEOFDAY )
|
||||
#define NEED_GETTIMEOFDAY 1
|
||||
#endif
|
||||
#if !defined( NEED_SNPRINTF )
|
||||
#define NEED_SNPRINTF 1
|
||||
#endif
|
||||
#if !defined( NEED_HSTRERROR )
|
||||
#define NEED_HSTRERROR 1
|
||||
#endif
|
||||
#if !defined( NEED_GETLASTERROR )
|
||||
#define NEED_GETLASTERROR 1
|
||||
#endif
|
||||
#if !defined( NEED_FIREWALL_ENABLE )
|
||||
#define NEED_FIREWALL_ENABLE 1
|
||||
#endif
|
||||
|
||||
typedef int socklen_t;
|
||||
#define MSG_NOSIGNAL 0
|
||||
#define MAKE_SOCKET_NONBLOCKING(x,r) \
|
||||
do { u_long _x = 1; (r) = ioctlsocket( (x), FIONBIO, &_x ); } while(0)
|
||||
#define NONBLOCK_MSG_SEND 0
|
||||
#define INIT_SOCKET_LIBRARY() \
|
||||
do { WSADATA wsaData; WSAStartup( MAKEWORD(2,2), &wsaData ); } while(0)
|
||||
|
||||
#pragma warning( disable: 4250 )
|
||||
|
||||
#define SIN_ADDR_UINT(x) \
|
||||
((uint&)(x).S_un.S_addr)
|
||||
#define BAD_SOCKET_FD 0xffffffffU
|
||||
|
||||
#else
|
||||
|
||||
// Linux features go here
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#if !defined( NEED_CLOSESOCKET )
|
||||
#define NEED_CLOSESOCKET 1
|
||||
#endif
|
||||
#if !defined( NEED_IOCTLSOCKET )
|
||||
#define NEED_IOCTLSOCKET 1
|
||||
#endif
|
||||
#if !defined( NEED_SHORT_TYPES )
|
||||
#define NEED_SHORT_TYPES 1
|
||||
#endif
|
||||
#if !defined( NEED_ERRNO )
|
||||
#define NEED_ERRNO 1
|
||||
#endif
|
||||
|
||||
extern int h_errno;
|
||||
// hack -- I don't make it non-blocking; instead, I pass
|
||||
// NONBLOCK_MSG_SEND for each call to sendto()
|
||||
#define MAKE_SOCKET_NONBLOCKING(x,r) do { (r) = 0; } while(0)
|
||||
#define NONBLOCK_MSG_SEND MSG_DONTWAIT
|
||||
#define INIT_SOCKET_LIBRARY() do {} while(0)
|
||||
|
||||
#if !defined( SOCKET )
|
||||
#define SOCKET int
|
||||
#endif
|
||||
#define SIN_ADDR_UINT(x) \
|
||||
((uint&)(x).s_addr)
|
||||
#define BAD_SOCKET_FD -1
|
||||
|
||||
#endif
|
||||
|
||||
#if NEED_CLOSESOCKET
|
||||
#define closesocket close
|
||||
#endif
|
||||
|
||||
#if NEED_PROTOENT
|
||||
struct protoent {
|
||||
int p_proto;
|
||||
};
|
||||
#endif
|
||||
#if NEED_GETPROTOBYNAME
|
||||
inline protoent * getprotobyname( char const * s ) {
|
||||
static protoent p;
|
||||
if( !strcmp( s, "udp" ) ) {
|
||||
p.p_proto = IPPROTO_UDP;
|
||||
return &p;
|
||||
}
|
||||
if( !strcmp( s, "tcp" ) ) {
|
||||
p.p_proto = IPPROTO_TCP;
|
||||
return &p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NEED_SHORT_TYPES
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
#endif
|
||||
|
||||
#if NEED_WINDOWS_POLL
|
||||
struct pollfd {
|
||||
SOCKET fd;
|
||||
unsigned short events;
|
||||
unsigned short revents;
|
||||
};
|
||||
#define POLLIN 0x1
|
||||
#define POLLPRI 0x2
|
||||
#define POLLOUT 0x4
|
||||
#define POLLERR 0x100
|
||||
#define POLLHUP 0x200
|
||||
#define POLLNVAL 0x8000
|
||||
int poll( pollfd * iofds, size_t count, int ms );
|
||||
#endif
|
||||
|
||||
#if NEED_GETTIMEOFDAY
|
||||
// this is not thread safe!
|
||||
void gettimeofday( timeval * otv, int );
|
||||
#endif
|
||||
|
||||
#if NEED_SNPRINTF
|
||||
inline int vsnprintf( char * buf, int size, char const * fmt, va_list vl ) {
|
||||
int r = _vsnprintf( buf, size, fmt, vl );
|
||||
if( r < 0 ) {
|
||||
buf[size-1] = 0;
|
||||
r = size-1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
inline int snprintf( char * buf, int size, char const * fmt, ... ) {
|
||||
va_list vl;
|
||||
va_start( vl, fmt );
|
||||
int r = vsnprintf( buf, size, fmt, vl );
|
||||
va_end( vl );
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NEED_HSTRERROR
|
||||
// NOT thread safe!
|
||||
inline char const * hstrerror( ulong ec ) {
|
||||
static char err[ 128 ];
|
||||
snprintf( err, 128, "host error 0x%lx", ec );
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NEED_GETLASTERROR
|
||||
#define SOCKET_ERRNO WSAGetLastError()
|
||||
inline bool SOCKET_WOULDBLOCK_ERROR( int e ) { return e == WSAEWOULDBLOCK; }
|
||||
inline bool SOCKET_NEED_REOPEN( int e ) { return e == WSAECONNRESET; }
|
||||
#endif
|
||||
|
||||
#if NEED_ERRNO
|
||||
#include <errno.h>
|
||||
#define SOCKET_ERRNO errno
|
||||
inline bool SOCKET_WOULDBLOCK_ERROR( int e ) { return e == EWOULDBLOCK; }
|
||||
inline bool SOCKET_NEED_REOPEN( int e ) { return false; }
|
||||
#endif
|
||||
|
||||
#if NEED_FIREWALL_ENABLE
|
||||
extern bool ENABLE_FIREWALL();
|
||||
#else
|
||||
#define ENABLE_FIREWALL() true
|
||||
#endif
|
||||
|
||||
#endif // sock_port_h
|
||||
|
25
Source/Core/Common/Src/SConscript
Normal file
25
Source/Core/Common/Src/SConscript
Normal file
@ -0,0 +1,25 @@
|
||||
Import('env')
|
||||
|
||||
files = ["Common.cpp",
|
||||
"CPUDetect.cpp",
|
||||
"DynamicLibrary.cpp",
|
||||
"Hash.cpp",
|
||||
"HTTP.cpp",
|
||||
"IniFile.cpp",
|
||||
"Logging.cpp",
|
||||
"MappedFile.cpp",
|
||||
"MathUtil.cpp",
|
||||
"MemArena.cpp",
|
||||
"MemoryUtil.cpp",
|
||||
"Plugin.cpp",
|
||||
"PortableSockets.cpp",
|
||||
"StringUtil.cpp",
|
||||
"TestFramework.cpp",
|
||||
"Timer.cpp",
|
||||
"Thread.cpp",
|
||||
"x64Emitter.cpp",
|
||||
"x64Analyzer.cpp",
|
||||
]
|
||||
|
||||
env_common = env.Copy(CXXFLAGS = " -fPIC ")
|
||||
env_common.StaticLibrary("common", files)
|
449
Source/Core/Common/Src/StringUtil.cpp
Normal file
449
Source/Core/Common/Src/StringUtil.cpp
Normal file
@ -0,0 +1,449 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "StringUtil.h"
|
||||
#include "TestFramework.h"
|
||||
|
||||
// faster than sscanf
|
||||
u32 AsciiToHex(const char* _szValue)
|
||||
{
|
||||
u32 value = 0;
|
||||
size_t finish = strlen(_szValue);
|
||||
|
||||
if (finish > 8)
|
||||
{
|
||||
finish = 8;
|
||||
}
|
||||
|
||||
for (size_t count = 0; count < finish; count++)
|
||||
{
|
||||
value <<= 4;
|
||||
|
||||
switch (_szValue[count])
|
||||
{
|
||||
case '0':
|
||||
break;
|
||||
|
||||
case '1':
|
||||
value += 1;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
value += 2;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
value += 3;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
value += 4;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
value += 5;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
value += 6;
|
||||
break;
|
||||
|
||||
case '7':
|
||||
value += 7;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
value += 8;
|
||||
break;
|
||||
|
||||
case '9':
|
||||
value += 9;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
value += 10;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
value += 10;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
value += 11;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
value += 11;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
value += 12;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
value += 12;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
value += 13;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
value += 13;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
value += 14;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
value += 14;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
value += 15;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
value += 15;
|
||||
break;
|
||||
|
||||
default:
|
||||
value >>= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(value);
|
||||
}
|
||||
|
||||
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
|
||||
{
|
||||
int writtenCount = vsnprintf(out, outsize, format, args);
|
||||
|
||||
if (writtenCount > 0)
|
||||
{
|
||||
out[writtenCount] = '\0';
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
out[outsize - 1] = '\0';
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expensive!
|
||||
void StringFromFormatV(std::string* out, const char* format, va_list args)
|
||||
{
|
||||
int writtenCount = -1;
|
||||
size_t newSize = strlen(format) + 16;
|
||||
char* buf = 0;
|
||||
|
||||
while (writtenCount < 0)
|
||||
{
|
||||
delete[] buf;
|
||||
buf = new char[newSize + 1];
|
||||
writtenCount = vsnprintf(buf, newSize, format, args);
|
||||
newSize *= 2;
|
||||
}
|
||||
|
||||
buf[writtenCount] = '\0';
|
||||
*out = buf;
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
|
||||
std::string StringFromFormat(const char* format, ...)
|
||||
{
|
||||
std::string temp;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
StringFromFormatV(&temp, format, args);
|
||||
va_end(args);
|
||||
return(temp);
|
||||
}
|
||||
|
||||
|
||||
void ToStringFromFormat(std::string* out, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
StringFromFormatV(out, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
// Turns " hej " into "hej". Also handles tabs.
|
||||
std::string StripSpaces(std::string s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)s.size(); i++)
|
||||
{
|
||||
if ((s[i] != ' ') && (s[i] != 9))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s = s.substr(i);
|
||||
|
||||
for (i = (int)s.size() - 1; i > 0; i--)
|
||||
{
|
||||
if ((s[i] != ' ') && (s[i] != 9))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(s.substr(0, i + 1));
|
||||
}
|
||||
|
||||
|
||||
// "\"hello\"" is turned to "hello"
|
||||
// This one assumes that the string has already been space stripped in both
|
||||
// ends, as done by StripSpaces above, for example.
|
||||
std::string StripQuotes(const std::string& s)
|
||||
{
|
||||
if ((s[0] == '\"') && (s[s.size() - 1] == '\"'))
|
||||
{
|
||||
return(s.substr(1, s.size() - 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
return(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TryParseInt(const char* str, int* outVal)
|
||||
{
|
||||
const char* s = str;
|
||||
int value = 0;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
char c = *s++;
|
||||
|
||||
if ((c < '0') || (c > '9'))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
value = value * 10 + (c - '0');
|
||||
}
|
||||
|
||||
*outVal = value;
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool TryParseBool(const char* str, bool* output)
|
||||
{
|
||||
if ((str[0] == '1') || !strcmp(str, "true") || !strcmp(str, "True") || !strcmp(str, "TRUE"))
|
||||
{
|
||||
*output = true;
|
||||
return(true);
|
||||
}
|
||||
else if (str[0] == '0' || !strcmp(str, "false") || !strcmp(str, "False") || !strcmp(str, "FALSE"))
|
||||
{
|
||||
*output = false;
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
std::string StringFromInt(int value)
|
||||
{
|
||||
char temp[16];
|
||||
sprintf(temp, "%i", value);
|
||||
return(std::string(temp));
|
||||
}
|
||||
|
||||
|
||||
std::string StringFromBool(bool value)
|
||||
{
|
||||
return(value ? "True" : "False");
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
||||
{
|
||||
char drive[_MAX_DRIVE];
|
||||
char dir[_MAX_DIR];
|
||||
char fname[_MAX_FNAME];
|
||||
char ext[_MAX_EXT];
|
||||
|
||||
if (_splitpath_s(full_path.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT) == 0)
|
||||
{
|
||||
if (_pPath)
|
||||
{
|
||||
*_pPath = std::string(drive) + std::string(dir);
|
||||
}
|
||||
|
||||
if (_pFilename != 0)
|
||||
{
|
||||
*_pFilename = fname;
|
||||
}
|
||||
|
||||
if (_pExtension != 0)
|
||||
{
|
||||
*_pExtension = ext;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
||||
{
|
||||
int last_slash = full_path.rfind('/');
|
||||
|
||||
if (last_slash == std::string::npos)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
int last_dot = full_path.rfind('.');
|
||||
|
||||
if ((last_dot == std::string::npos) || (last_dot < last_slash))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (_pPath)
|
||||
{
|
||||
*_pPath = full_path.substr(0, last_slash + 1);
|
||||
}
|
||||
|
||||
if (_pFilename)
|
||||
{
|
||||
*_pFilename = full_path.substr(last_slash + 1, last_dot - (last_slash + 1));
|
||||
}
|
||||
|
||||
if (_pExtension)
|
||||
{
|
||||
*_pExtension = full_path.substr(last_dot + 1);
|
||||
}
|
||||
else if (_pFilename)
|
||||
{
|
||||
*_pFilename += full_path.substr(last_dot);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
|
||||
{
|
||||
_CompleteFilename = _Path;
|
||||
|
||||
// check for seperator
|
||||
if (_CompleteFilename[_CompleteFilename.size() - 1] != '\\')
|
||||
{
|
||||
_CompleteFilename += _T("\\");
|
||||
}
|
||||
|
||||
// add the filename
|
||||
_CompleteFilename += _Filename;
|
||||
}
|
||||
|
||||
|
||||
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& output)
|
||||
{
|
||||
output.clear();
|
||||
|
||||
size_t offset = 0;
|
||||
size_t delimIndex = 0;
|
||||
|
||||
delimIndex = str.find(delim, offset);
|
||||
|
||||
while (delimIndex != std::string::npos)
|
||||
{
|
||||
output.push_back(str.substr(offset, delimIndex - offset));
|
||||
offset += delimIndex - offset + delim.length();
|
||||
delimIndex = str.find(delim, offset);
|
||||
}
|
||||
|
||||
output.push_back(str.substr(offset));
|
||||
}
|
||||
|
||||
|
||||
bool TryParseUInt(const std::string& str, u32* output)
|
||||
{
|
||||
if (!strcmp(str.substr(0, 2).c_str(), "0x") || !strcmp(str.substr(0, 2).c_str(), "0X"))
|
||||
{
|
||||
return(sscanf(str.c_str() + 2, "%x", output) > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return(sscanf(str.c_str(), "%d", output) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ChooseStringFrom(const char* str, const char* * items)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (items[i] != 0)
|
||||
{
|
||||
if (!strcmp(str, items[i]))
|
||||
{
|
||||
return(i);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
// Hmm, sometimes this test doesn't get run :P
|
||||
TEST(splitStringTest)
|
||||
{
|
||||
/*
|
||||
std::string orig = "abc:def";
|
||||
std::vector<std::string> split;
|
||||
SplitString(orig, std::string(":"), split);
|
||||
CHECK(split.size() == 2);
|
||||
CHECK(!strcmp(split[0].c_str(), "abc"));
|
||||
CHECK(!strcmp(split[1].c_str(), "def"));
|
||||
|
||||
orig = "abc";
|
||||
SplitString(orig, std::string(":"), split);
|
||||
CHECK(split.size() == 1);
|
||||
orig = ":";
|
||||
SplitString(orig, std::string(":"), split);
|
||||
CHECK(split.size() == 2);*/
|
||||
}
|
75
Source/Core/Common/Src/StringUtil.h
Normal file
75
Source/Core/Common/Src/StringUtil.h
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _STRINGUTIL_H
|
||||
#define _STRINGUTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
std::string StringFromFormat(const char* format, ...);
|
||||
void ToStringFromFormat(std::string* out, const char* format, ...);
|
||||
|
||||
|
||||
// Expensive!
|
||||
void StringFromFormatV(std::string* out, const char* format, va_list args);
|
||||
|
||||
|
||||
// Cheap!
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
|
||||
|
||||
|
||||
template<size_t Count>
|
||||
inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
CharArrayFromFormatV(out, Count, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
std::string StripSpaces(std::string s);
|
||||
std::string StripQuotes(const std::string& s);
|
||||
|
||||
|
||||
std::string StringFromInt(int value);
|
||||
std::string StringFromBool(bool value);
|
||||
|
||||
bool TryParseInt(const char* str, int* outVal);
|
||||
bool TryParseBool(const char* str, bool* output);
|
||||
bool TryParseUInt(const std::string& str, u32* output);
|
||||
|
||||
|
||||
// TODO: kill this
|
||||
u32 AsciiToHex(const char* ascii);
|
||||
|
||||
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& output);
|
||||
int ChooseStringFrom(const char* str, const char* * items);
|
||||
|
||||
|
||||
// filehelper
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension);
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename);
|
||||
|
||||
|
||||
#endif
|
||||
|
38
Source/Core/Common/Src/TestFramework.cpp
Normal file
38
Source/Core/Common/Src/TestFramework.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "TestFramework.h"
|
||||
|
||||
namespace __test
|
||||
{
|
||||
int numTests;
|
||||
int numTestsFailed;
|
||||
}
|
||||
|
||||
|
||||
int GetNumTests()
|
||||
{
|
||||
return(__test::numTests);
|
||||
}
|
||||
|
||||
|
||||
int GetNumTestsFailed()
|
||||
{
|
||||
return(__test::numTestsFailed);
|
||||
}
|
||||
|
||||
|
100
Source/Core/Common/Src/TestFramework.h
Normal file
100
Source/Core/Common/Src/TestFramework.h
Normal file
@ -0,0 +1,100 @@
|
||||
// Stupidly simple automated testing framework
|
||||
// by ector
|
||||
|
||||
// licence: Public Domain
|
||||
|
||||
// If TESTING_ENABLE is true, all tests across the project will run before main().
|
||||
// If it's false, all tests will be destroyed by the linker, hopefully.
|
||||
|
||||
// Unfortunately, MSVC:s library linker seems to kill off unreferenced objects, even if the
|
||||
// initialization has side effects. This makes this framework not work properly :(
|
||||
// TODO(ector): Find solution.
|
||||
|
||||
// TODO(ector): make sure tests are destroyed and that things compile without TESTING_ENABLE :P
|
||||
|
||||
#define TESTING_ENABLE
|
||||
|
||||
#ifndef _TEST_FRAMEWORK_H
|
||||
#define _TEST_FRAMEWORK_H
|
||||
|
||||
#include "Common.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef TESTING_ENABLE
|
||||
|
||||
namespace __test
|
||||
{
|
||||
extern int numTests;
|
||||
extern int numTestsFailed;
|
||||
}
|
||||
|
||||
struct TestRunnah
|
||||
{
|
||||
const char* filename;
|
||||
const char* function;
|
||||
TestRunnah(const char* _filename, const char* _function)
|
||||
: filename(_filename), function(_function) {}
|
||||
|
||||
|
||||
bool AssertTrue(bool value, int line)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
char string[256];
|
||||
sprintf(string, "%s:%s:%i: %s", filename, function, line, "failed");
|
||||
PanicAlert("Test Results: %s", string);
|
||||
TestFailed();
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
bool AssertEqual(T a, T b, int line)
|
||||
{
|
||||
if (!(a == b))
|
||||
{
|
||||
// TODO(ector) : better output
|
||||
char string[256];
|
||||
sprintf(string, "%s:%s:%i: %s", filename, function, line, "failed");
|
||||
PanicAlert("Test Results: %s", string);
|
||||
TestFailed();
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestFailed()
|
||||
{
|
||||
__test::numTestsFailed++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define TEST(a) \
|
||||
void TEST_ ## a(TestRunnah * __tr); \
|
||||
struct DUMMY_ ## a \
|
||||
: public TestRunnah { \
|
||||
DUMMY_ ## a() \
|
||||
: TestRunnah(__FILE__, # a) {\
|
||||
TEST_ ## a(this); __test::numTests++;} }; \
|
||||
DUMMY_ ## a ddummy_ ## a; \
|
||||
void TEST_ ## a(TestRunnah * __tr)
|
||||
|
||||
#else // TESTING_ENABLE
|
||||
|
||||
#define TEST(a) \
|
||||
void TEST_ ## a(TestRunnah * __tr) \
|
||||
|
||||
#endif
|
||||
|
||||
#define CHECK(a) if (!__tr->AssertTrue(a, __LINE__)){return;}
|
||||
#define CHECK_EQ(a, b) if (!__tr->AssertEqual(a, b, __LINE__)){return;}
|
||||
|
||||
int GetNumTests();
|
||||
int GetNumTestsFailed();
|
||||
|
||||
|
||||
#endif
|
346
Source/Core/Common/Src/Thread.cpp
Normal file
346
Source/Core/Common/Src/Thread.cpp
Normal file
@ -0,0 +1,346 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif __GNUC__
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error unsupported platform
|
||||
#endif
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CriticalSection::CriticalSection(int spincount)
|
||||
{
|
||||
if (spincount)
|
||||
{
|
||||
InitializeCriticalSectionAndSpinCount(§ion, spincount);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeCriticalSection(§ion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CriticalSection::~CriticalSection()
|
||||
{
|
||||
// No need to do anything
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Enter()
|
||||
{
|
||||
EnterCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
bool CriticalSection::TryEnter()
|
||||
{
|
||||
return(TryEnterCriticalSection(§ion) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Leave()
|
||||
{
|
||||
LeaveCriticalSection(§ion);
|
||||
}
|
||||
|
||||
|
||||
Thread::Thread(ThreadFunc function, void* arg)
|
||||
: m_hThread(NULL), m_threadId(0)
|
||||
{
|
||||
m_hThread = CreateThread(
|
||||
0, // Security attributes
|
||||
0, // Stack size
|
||||
function,
|
||||
arg,
|
||||
0,
|
||||
&m_threadId);
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
WaitForDeath();
|
||||
}
|
||||
|
||||
|
||||
void Thread::WaitForDeath()
|
||||
{
|
||||
if (m_hThread)
|
||||
{
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
CloseHandle(m_hThread);
|
||||
m_hThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Thread::SetAffinity(int mask)
|
||||
{
|
||||
SetThreadAffinityMask(m_hThread, mask);
|
||||
}
|
||||
|
||||
|
||||
void Thread::SetCurrentThreadAffinity(int mask)
|
||||
{
|
||||
SetThreadAffinityMask(GetCurrentThread(), mask);
|
||||
}
|
||||
|
||||
|
||||
Event::Event()
|
||||
{
|
||||
m_hEvent = 0;
|
||||
}
|
||||
|
||||
|
||||
void Event::Init()
|
||||
{
|
||||
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
}
|
||||
|
||||
|
||||
void Event::Shutdown()
|
||||
{
|
||||
CloseHandle(m_hEvent);
|
||||
m_hEvent = 0;
|
||||
}
|
||||
|
||||
|
||||
void Event::Set()
|
||||
{
|
||||
SetEvent(m_hEvent);
|
||||
}
|
||||
|
||||
|
||||
void Event::Wait()
|
||||
{
|
||||
WaitForSingleObject(m_hEvent, INFINITE);
|
||||
}
|
||||
|
||||
|
||||
void SleepCurrentThread(int ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // must be 0x1000
|
||||
LPCSTR szName; // pointer to name (in user addr space)
|
||||
DWORD dwThreadID; // thread ID (-1=caller thread)
|
||||
DWORD dwFlags; // reserved for future use, must be zero
|
||||
} THREADNAME_INFO;
|
||||
// Usage: SetThreadName (-1, "MainThread");
|
||||
//
|
||||
// Sets the debugger-visible name of the current thread.
|
||||
// Uses undocumented (actually, it is now documented) trick.
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
|
||||
|
||||
void SetCurrentThreadName(const TCHAR* szThreadName)
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
#ifdef UNICODE
|
||||
//TODO: Find the proper way to do this.
|
||||
char tname[256];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < _tcslen(szThreadName); i++)
|
||||
{
|
||||
tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
|
||||
}
|
||||
|
||||
tname[i] = 0;
|
||||
info.szName = tname;
|
||||
#else
|
||||
info.szName = szThreadName;
|
||||
#endif
|
||||
|
||||
info.dwThreadID = -1; //dwThreadID;
|
||||
info.dwFlags = 0;
|
||||
__try
|
||||
{
|
||||
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||
{}
|
||||
}
|
||||
|
||||
|
||||
#elif __GNUC__
|
||||
CriticalSection::CriticalSection(int spincount_unused)
|
||||
{
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
||||
|
||||
CriticalSection::~CriticalSection()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Enter()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
bool CriticalSection::TryEnter()
|
||||
{
|
||||
return(!pthread_mutex_trylock(&mutex));
|
||||
}
|
||||
|
||||
|
||||
void CriticalSection::Leave()
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
Thread::Thread(ThreadFunc function, void* arg)
|
||||
: thread_id(0)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, 1024 * 1024);
|
||||
pthread_create(&thread_id, &attr, function, arg);
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
WaitForDeath();
|
||||
}
|
||||
|
||||
|
||||
void Thread::WaitForDeath()
|
||||
{
|
||||
if (thread_id)
|
||||
{
|
||||
void* exit_status;
|
||||
pthread_join(thread_id, &exit_status);
|
||||
thread_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Thread::SetAffinity(int mask)
|
||||
{
|
||||
// This is non-standard
|
||||
#ifdef __linux__
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
||||
for (int i = 0; i < sizeof(mask) * 8; i++)
|
||||
{
|
||||
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
||||
}
|
||||
|
||||
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Thread::SetCurrentThreadAffinity(int mask)
|
||||
{
|
||||
#ifdef __linux__
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
||||
for (size_t i = 0; i < sizeof(mask) * 8; i++)
|
||||
{
|
||||
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
||||
}
|
||||
|
||||
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SleepCurrentThread(int ms)
|
||||
{
|
||||
usleep(1000 * ms);
|
||||
}
|
||||
|
||||
|
||||
void SetCurrentThreadName(const TCHAR* szThreadName)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
Event::Event()
|
||||
{
|
||||
is_set_ = false;
|
||||
}
|
||||
|
||||
|
||||
void Event::Init()
|
||||
{
|
||||
pthread_cond_init(&event_, 0);
|
||||
pthread_mutex_init(&mutex_, 0);
|
||||
}
|
||||
|
||||
|
||||
void Event::Shutdown()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
pthread_cond_destroy(&event_);
|
||||
}
|
||||
|
||||
|
||||
void Event::Set()
|
||||
{
|
||||
pthread_mutex_lock(&mutex_);
|
||||
|
||||
if (!is_set_)
|
||||
{
|
||||
is_set_ = true;
|
||||
pthread_cond_signal(&event_);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
|
||||
|
||||
void Event::Wait()
|
||||
{
|
||||
pthread_mutex_lock(&mutex_);
|
||||
|
||||
while (!is_set_)
|
||||
{
|
||||
pthread_cond_wait(&event_, &mutex_);
|
||||
}
|
||||
|
||||
is_set_ = false;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
} // end of namespace Common
|
109
Source/Core/Common/Src/Thread.h
Normal file
109
Source/Core/Common/Src/Thread.h
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _THREAD_H
|
||||
#define _THREAD_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define THREAD_RETURN DWORD WINAPI
|
||||
#else
|
||||
#define THREAD_RETURN void*
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class CriticalSection
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CRITICAL_SECTION section;
|
||||
#elif __GNUC__
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
public:
|
||||
|
||||
CriticalSection(int spincount = 1000);
|
||||
~CriticalSection();
|
||||
void Enter();
|
||||
bool TryEnter();
|
||||
void Leave();
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef DWORD (WINAPI * ThreadFunc)(void* arg);
|
||||
#elif __GNUC__
|
||||
typedef void* (*ThreadFunc)(void* arg);
|
||||
#endif
|
||||
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
|
||||
Thread(ThreadFunc entry, void* arg);
|
||||
~Thread();
|
||||
|
||||
void WaitForDeath();
|
||||
void SetAffinity(int mask);
|
||||
static void SetCurrentThreadAffinity(int mask);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE m_hThread;
|
||||
DWORD m_threadId;
|
||||
#elif __GNUC__
|
||||
pthread_t thread_id;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
|
||||
Event();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void Set();
|
||||
void Wait();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE m_hEvent;
|
||||
#elif __GNUC__
|
||||
bool is_set_;
|
||||
pthread_cond_t event_;
|
||||
pthread_mutex_t mutex_;
|
||||
#endif
|
||||
};
|
||||
|
||||
void SleepCurrentThread(int ms);
|
||||
|
||||
void SetCurrentThreadName(const char* name);
|
||||
} // end of namespace Common
|
||||
|
||||
#endif
|
99
Source/Core/Common/Src/Timer.cpp
Normal file
99
Source/Core/Common/Src/Timer.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "Timer.H"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <sys/timeb.h>
|
||||
|
||||
u32 timeGetTime()
|
||||
{
|
||||
struct timeb t;
|
||||
ftime(&t);
|
||||
return((u32)(t.time * 1000 + t.millitm));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace Common
|
||||
{
|
||||
Timer::Timer(void)
|
||||
: m_LastTime(0)
|
||||
{
|
||||
Update();
|
||||
|
||||
#ifdef _WIN32
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Timer::Update(void)
|
||||
{
|
||||
m_LastTime = timeGetTime();
|
||||
//TODO(ector) - QPF
|
||||
}
|
||||
|
||||
|
||||
s64 Timer::GetTimeDifference(void)
|
||||
{
|
||||
return(timeGetTime() - m_LastTime);
|
||||
}
|
||||
|
||||
|
||||
void Timer::IncreaseResolution()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Timer::RestoreResolution()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
void _time64(u64* t)
|
||||
{
|
||||
*t = 0; //TODO
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
u64 Timer::GetTimeSinceJan1970(void)
|
||||
{
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
return((u64)ltime);
|
||||
}
|
||||
} // end of namespace Common
|
49
Source/Core/Common/Src/Timer.h
Normal file
49
Source/Core/Common/Src/Timer.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _TIMER_H
|
||||
#define _TIMER_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
|
||||
Timer();
|
||||
|
||||
void Update();
|
||||
|
||||
|
||||
// Always in milliseconds, regardless of alternative internal representation
|
||||
s64 GetTimeDifference(void);
|
||||
|
||||
static void IncreaseResolution();
|
||||
static void RestoreResolution();
|
||||
static u64 GetTimeSinceJan1970();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
u64 m_LastTime;
|
||||
u64 m_frequency;
|
||||
};
|
||||
} // end of namespace Common
|
||||
|
||||
#endif
|
18
Source/Core/Common/Src/stdafx.cpp
Normal file
18
Source/Core/Common/Src/stdafx.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
33
Source/Core/Common/Src/stdafx.h
Normal file
33
Source/Core/Common/Src/stdafx.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _WIN32_WINNT 0x501
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0500 // Default value is 0x0400
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <vector>
|
||||
|
219
Source/Core/Common/Src/x64Analyzer.cpp
Normal file
219
Source/Core/Common/Src/x64Analyzer.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include "x64Analyzer.h"
|
||||
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
|
||||
{
|
||||
unsigned const char *startCodePtr = codePtr;
|
||||
u8 rex = 0;
|
||||
u8 codeByte = 0;
|
||||
u8 codeByte2 = 0;
|
||||
|
||||
//Check for regular prefix
|
||||
info.operandSize = 4;
|
||||
info.zeroExtend = false;
|
||||
|
||||
int addressSize = 8;
|
||||
u8 modRMbyte = 0;
|
||||
u8 sibByte = 0;
|
||||
bool hasModRM = false;
|
||||
bool hasSIBbyte = false;
|
||||
bool hasDisplacement = false;
|
||||
info.hasImmediate = false;
|
||||
|
||||
int displacementSize = 0;
|
||||
|
||||
if (*codePtr == 0x66)
|
||||
{
|
||||
info.operandSize = 2;
|
||||
codePtr++;
|
||||
}
|
||||
else if (*codePtr == 0x67)
|
||||
{
|
||||
addressSize = 4;
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
//Check for REX prefix
|
||||
if ((*codePtr & 0xF0) == 0x40)
|
||||
{
|
||||
rex = *codePtr;
|
||||
if (rex & 8) //REX.W
|
||||
{
|
||||
info.operandSize = 8;
|
||||
}
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
codeByte = *codePtr++;
|
||||
|
||||
// Skip two-byte opcode byte
|
||||
bool twoByte = false;
|
||||
if(codeByte == 0x0F)
|
||||
{
|
||||
twoByte = true;
|
||||
codeByte2 = *codePtr++;
|
||||
}
|
||||
|
||||
if (!twoByte)
|
||||
{
|
||||
if ((codeByte & 0xF0) == 0x80 ||
|
||||
(codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02)
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D ||
|
||||
(codeByte2 & 0xF0) == 0x30 ||
|
||||
codeByte2 == 0x77 ||
|
||||
(codeByte2 & 0xF0) == 0x80 ||
|
||||
(codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02 ||
|
||||
(codeByte2 & 0xF8) == 0xC8)
|
||||
{
|
||||
// No mod R/M byte
|
||||
}
|
||||
else
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasModRM)
|
||||
{
|
||||
ModRM mrm(modRMbyte, rex);
|
||||
info.regOperandReg = mrm.reg;
|
||||
if (mrm.mod < 3)
|
||||
{
|
||||
if (mrm.rm == 4)
|
||||
{
|
||||
//SIB byte
|
||||
sibByte = *codePtr++;
|
||||
info.scaledReg = (sibByte >> 3) & 7;
|
||||
info.otherReg = (sibByte & 7);
|
||||
if (rex & 2) info.scaledReg += 8;
|
||||
if (rex & 1) info.otherReg += 8;
|
||||
hasSIBbyte = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//info.scaledReg =
|
||||
}
|
||||
}
|
||||
if (mrm.mod == 1 || mrm.mod == 2)
|
||||
{
|
||||
hasDisplacement = true;
|
||||
if (mrm.mod == 1)
|
||||
displacementSize = 1;
|
||||
else
|
||||
displacementSize = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementSize == 1)
|
||||
info.displacement = (s32)(s8)*codePtr;
|
||||
else
|
||||
info.displacement = *((s32 *)codePtr);
|
||||
codePtr += displacementSize;
|
||||
|
||||
|
||||
if (accessType == 1)
|
||||
{
|
||||
//Write access
|
||||
switch (codeByte)
|
||||
{
|
||||
case 0xC6: //move 8-bit immediate
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *codePtr;
|
||||
codePtr++; //move past immediate
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7: //move 16 or 32-bit immediate, easiest case for writes
|
||||
{
|
||||
if (info.operandSize == 2)
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *(u16*)codePtr;
|
||||
codePtr += 2;
|
||||
}
|
||||
else if (info.operandSize == 4)
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
else if (info.operandSize == 8)
|
||||
{
|
||||
info.zeroExtend = true;
|
||||
info.immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x89: //move reg to memory
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//mov eax,dword ptr [rax] == 8b 00
|
||||
switch (codeByte)
|
||||
{
|
||||
case 0x0F:
|
||||
switch (codeByte2)
|
||||
{
|
||||
case 0xB6: //movzx on byte
|
||||
info.zeroExtend = true;
|
||||
info.operandSize = 1;
|
||||
break;
|
||||
case 0xB7: //movzx on short
|
||||
info.zeroExtend = true;
|
||||
info.operandSize = 2;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 0x8a:
|
||||
if (info.operandSize == 4)
|
||||
{
|
||||
info.operandSize = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
case 0x8b:
|
||||
break; //it's OK don't need to do anything
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
info.instructionSize = (int)(codePtr - startCodePtr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
54
Source/Core/Common/Src/x64Analyzer.h
Normal file
54
Source/Core/Common/Src/x64Analyzer.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _X64ANALYZER_H
|
||||
#define _X64ANALYZER_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
struct InstructionInfo
|
||||
{
|
||||
int operandSize; //8, 16, 32, 64
|
||||
int instructionSize;
|
||||
int regOperandReg;
|
||||
int otherReg;
|
||||
int scaledReg;
|
||||
bool zeroExtend;
|
||||
bool hasImmediate;
|
||||
u64 immediate;
|
||||
s32 displacement;
|
||||
};
|
||||
|
||||
struct ModRM
|
||||
{
|
||||
int mod, reg, rm;
|
||||
ModRM(u8 modRM, u8 rex)
|
||||
{
|
||||
mod = modRM >> 6;
|
||||
reg = ((modRM >> 3) & 7) | ((rex & 4)?8:0);
|
||||
rm = modRM & 7;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum AccessType{
|
||||
OP_ACCESS_READ = 0,
|
||||
OP_ACCESS_WRITE = 1
|
||||
};
|
||||
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType);
|
||||
|
||||
#endif
|
1406
Source/Core/Common/Src/x64Emitter.cpp
Normal file
1406
Source/Core/Common/Src/x64Emitter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
542
Source/Core/Common/Src/x64Emitter.h
Normal file
542
Source/Core/Common/Src/x64Emitter.h
Normal file
@ -0,0 +1,542 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _DOLPHIN_INTEL_CODEGEN
|
||||
#define _DOLPHIN_INTEL_CODEGEN
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace Gen
|
||||
{
|
||||
enum X64Reg
|
||||
{
|
||||
EAX = 0, EBX = 3, ECX = 1, EDX = 2,
|
||||
ESI = 6, EDI = 7, EBP = 5, ESP = 4,
|
||||
|
||||
RAX = 0, RBX = 3, RCX = 1, RDX = 2,
|
||||
RSI = 6, RDI = 7, RBP = 5, RSP = 4,
|
||||
R8 = 8, R9 = 9, R10 = 10,R11 = 11,
|
||||
R12 = 12,R13 = 13,R14 = 14,R15 = 15,
|
||||
|
||||
AL = 0, BL = 3, CL = 1, DL = 2,
|
||||
AH = 4, BH = 7, CH = 5, DH = 6,
|
||||
|
||||
AX = 0, BX = 3, CX = 1, DX = 2,
|
||||
SI = 6, DI = 7, BP = 5, SP = 4,
|
||||
|
||||
XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
||||
XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15,
|
||||
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum CCFlags
|
||||
{
|
||||
CC_O = 0,
|
||||
CC_NO = 1,
|
||||
CC_B = 2, CC_C = 2, CC_NAE = 2,
|
||||
CC_NB = 3, CC_NC = 3, CC_AE = 3,
|
||||
CC_Z = 4, CC_E = 4,
|
||||
CC_NZ = 5, CC_NE = 5,
|
||||
CC_BE = 6, CC_NA = 6,
|
||||
CC_NBE = 7, CC_A = 7,
|
||||
CC_S = 8,
|
||||
CC_NS = 9,
|
||||
CC_P = 0xA, CC_PE = 0xA,
|
||||
CC_NP = 0xB, CC_PO = 0xB,
|
||||
CC_L = 0xC, CC_NGE = 0xC,
|
||||
CC_NL = 0xD, CC_GE = 0xD,
|
||||
CC_LE = 0xE, CC_NG = 0xE,
|
||||
CC_NLE = 0xF, CC_G = 0xF
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NUMGPRs = 16,
|
||||
NUMXMMs = 16,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCALE_NONE = 0,
|
||||
SCALE_1 = 1,
|
||||
SCALE_2 = 2,
|
||||
SCALE_4 = 4,
|
||||
SCALE_8 = 8,
|
||||
SCALE_ATREG = 16,
|
||||
SCALE_RIP = 0xFF,
|
||||
SCALE_IMM8 = 0xF0,
|
||||
SCALE_IMM16 = 0xF1,
|
||||
SCALE_IMM32 = 0xF2,
|
||||
SCALE_IMM64 = 0xF3,
|
||||
};
|
||||
|
||||
void SetCodePtr(u8 *ptr);
|
||||
void ReserveCodeSpace(int bytes);
|
||||
const u8 *AlignCode4();
|
||||
const u8 *AlignCode16();
|
||||
const u8 *AlignCodePage();
|
||||
const u8 *GetCodePtr();
|
||||
u8 *GetWritableCodePtr();
|
||||
|
||||
enum NormalOp {
|
||||
nrmADD,
|
||||
nrmADC,
|
||||
nrmSUB,
|
||||
nrmSBB,
|
||||
nrmAND,
|
||||
nrmOR ,
|
||||
nrmXOR,
|
||||
nrmMOV,
|
||||
nrmTEST,
|
||||
nrmCMP,
|
||||
nrmXCHG,
|
||||
};
|
||||
|
||||
// Make the generation routine examine which direction to go
|
||||
// probably has to be a static
|
||||
|
||||
// RIP addressing does not benefit from micro op fusion on Core arch
|
||||
struct OpArg
|
||||
{
|
||||
OpArg() {} //dummy op arg, used for storage
|
||||
OpArg(u64 _offset, int _scale, X64Reg rmReg = RAX, X64Reg scaledReg = RAX)
|
||||
{
|
||||
operandReg = 0;
|
||||
scale = (u8)_scale;
|
||||
offsetOrBaseReg = (u8)rmReg;
|
||||
indexReg = (u8)scaledReg;
|
||||
//if scale == 0 never mind offseting
|
||||
offset = _offset;
|
||||
}
|
||||
void WriteRex(bool op64, int customOp = -1) const;
|
||||
void WriteRest(int extraBytes=0, X64Reg operandReg=(X64Reg)0xFF) const;
|
||||
void WriteSingleByteOp(u8 op, X64Reg operandReg, int bits);
|
||||
//This one is public - must be written to
|
||||
u64 offset; //use RIP-relative as much as possible - avoid 64-bit immediates at all costs
|
||||
u8 operandReg;
|
||||
|
||||
void WriteNormalOp(bool toRM, NormalOp op, const OpArg &operand, int bits) const;
|
||||
bool IsImm() const {return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || scale == SCALE_IMM64;}
|
||||
bool IsSimpleReg() const {return scale == SCALE_NONE;}
|
||||
|
||||
bool CanDoOpWith(OpArg &other) const
|
||||
{
|
||||
if (IsSimpleReg()) return true;
|
||||
if (!IsSimpleReg() && !other.IsSimpleReg() && !other.IsImm()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int GetImmBits() const
|
||||
{
|
||||
switch (scale)
|
||||
{
|
||||
case SCALE_IMM8: return 8;
|
||||
case SCALE_IMM16: return 16;
|
||||
case SCALE_IMM32: return 32;
|
||||
case SCALE_IMM64: return 64;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
X64Reg GetSimpleReg() const
|
||||
{
|
||||
if (scale == SCALE_NONE)
|
||||
return (X64Reg)offsetOrBaseReg;
|
||||
else
|
||||
return INVALID_REG;
|
||||
}
|
||||
private:
|
||||
u8 scale;
|
||||
u8 offsetOrBaseReg;
|
||||
u8 indexReg;
|
||||
};
|
||||
|
||||
inline OpArg M(void *ptr) {return OpArg((u64)ptr, (int)SCALE_RIP);}
|
||||
inline OpArg R(X64Reg value) {return OpArg(0, SCALE_NONE, value);}
|
||||
inline OpArg MatR(X64Reg value) {return OpArg(0, SCALE_ATREG, value);}
|
||||
inline OpArg MDisp(X64Reg value, int offset) {
|
||||
return OpArg((u32)offset, SCALE_ATREG, value); }
|
||||
inline OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset)
|
||||
{
|
||||
return OpArg(offset, scale, base, scaled);
|
||||
}
|
||||
inline OpArg Imm8 (u8 imm) {return OpArg(imm, SCALE_IMM8);}
|
||||
inline OpArg Imm16(u16 imm) {return OpArg(imm, SCALE_IMM16);} //rarely used
|
||||
inline OpArg Imm32(u32 imm) {return OpArg(imm, SCALE_IMM32);}
|
||||
inline OpArg Imm64(u64 imm) {return OpArg(imm, SCALE_IMM64);}
|
||||
#ifdef _M_X64
|
||||
inline OpArg ImmPtr(void* imm) {return Imm64((u64)imm);}
|
||||
#else
|
||||
inline OpArg ImmPtr(void* imm) {return Imm32((u32)imm);}
|
||||
#endif
|
||||
|
||||
void INT3();
|
||||
void NOP(int count = 1); //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
|
||||
void PAUSE();
|
||||
void RET();
|
||||
void STC();
|
||||
void CLC();
|
||||
void CMC();
|
||||
void PUSH(X64Reg reg);
|
||||
void POP(X64Reg reg);
|
||||
void PUSH(int bits, const OpArg ®);
|
||||
void POP(int bits, const OpArg ®);
|
||||
void PUSHF();
|
||||
void POPF();
|
||||
|
||||
typedef const u8* JumpTarget;
|
||||
|
||||
struct FixupBranch
|
||||
{
|
||||
u8 *ptr;
|
||||
int type; //0 = 8bit 1 = 32bit
|
||||
};
|
||||
|
||||
FixupBranch J(bool force5bytes = false);
|
||||
|
||||
void JMP(const u8 * addr, bool force5Bytes = false);
|
||||
void JMP(OpArg arg);
|
||||
void JMPptr(const OpArg &arg);
|
||||
void JMPself(); //infinite loop!
|
||||
|
||||
void CALL(void *fnptr);
|
||||
void CALLptr(OpArg arg);
|
||||
|
||||
FixupBranch J_CC(CCFlags conditionCode, bool force5bytes = false);
|
||||
void J_CC(CCFlags conditionCode, JumpTarget target);
|
||||
void J_CC(CCFlags conditionCode, const u8 * addr, bool force5Bytes = false);
|
||||
|
||||
void SetJumpTarget(const FixupBranch &branch);
|
||||
|
||||
//WARNING - INC and DEC slow on Intel Core, but not on AMD, since it creates
|
||||
//false flags dependencies because they only update a subset of the flags
|
||||
|
||||
// ector - I hereby BAN inc and dec due to their horribleness :P
|
||||
// void INC(int bits, OpArg arg);
|
||||
// void DEC(int bits, OpArg arg);
|
||||
|
||||
void SETcc(CCFlags flag, OpArg dest);
|
||||
// Note: CMOV brings small if any benefit on current cpus, unfortunately.
|
||||
void CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag);
|
||||
|
||||
void LFENCE();
|
||||
void MFENCE();
|
||||
void SFENCE();
|
||||
|
||||
void BSF(int bits, X64Reg dest, OpArg src); //bottom bit to top bit
|
||||
void BSR(int bits, X64Reg dest, OpArg src); //top bit to bottom bit
|
||||
|
||||
//These two can not be executed on early Intel 64-bit CPU:s, only on AMD!
|
||||
|
||||
void LAHF(); // 3 cycle vector path
|
||||
void SAHF(); // direct path fast
|
||||
|
||||
//Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU
|
||||
//LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XLAT, REP MOVSB/MOVSD, REP SCASD + other string instr.,
|
||||
|
||||
//Actually REP MOVSD could be useful :P
|
||||
|
||||
void MOVNTI(int bits, OpArg dest, X64Reg src);
|
||||
|
||||
void MUL(int bits, OpArg src); //UNSIGNED
|
||||
void DIV(int bits, OpArg src);
|
||||
void IMUL(int bits, OpArg src); //SIGNED
|
||||
void IDIV(int bits, OpArg src);
|
||||
//TODO: alternate IMUL forms
|
||||
|
||||
void NEG(int bits, OpArg src);
|
||||
void NOT(int bits, OpArg src);
|
||||
|
||||
void ROL(int bits, OpArg dest, OpArg shift);
|
||||
void ROR(int bits, OpArg dest, OpArg shift);
|
||||
void RCL(int bits, OpArg dest, OpArg shift);
|
||||
void RCR(int bits, OpArg dest, OpArg shift);
|
||||
void SHL(int bits, OpArg dest, OpArg shift);
|
||||
void SHR(int bits, OpArg dest, OpArg shift);
|
||||
void SAR(int bits, OpArg dest, OpArg shift);
|
||||
|
||||
|
||||
void CWD(int bits = 16);
|
||||
inline void CDQ() {CWD(32);}
|
||||
inline void CQO() {CWD(64);}
|
||||
void CBW(int bits = 8);
|
||||
inline void CWDE() {CBW(16);}
|
||||
inline void CDQE() {CBW(32);}
|
||||
|
||||
void LEA(int bits, X64Reg dest, OpArg src);
|
||||
|
||||
|
||||
enum PrefetchLevel
|
||||
{
|
||||
PF_NTA, //Non-temporal (data used once and only once)
|
||||
PF_T0, //All cache levels
|
||||
PF_T1, //Levels 2+ (aliased to T0 on AMD)
|
||||
PF_T2, //Levels 3+ (aliased to T0 on AMD)
|
||||
};
|
||||
void PREFETCH(PrefetchLevel level, OpArg arg);
|
||||
|
||||
|
||||
void ADD (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void ADC (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void SUB (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void SBB (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void AND (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void OR (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void XOR (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void MOV (int bits, const OpArg &a1, const OpArg &a2);
|
||||
void TEST(int bits, const OpArg &a1, const OpArg &a2);
|
||||
void CMP (int bits, const OpArg &a1, const OpArg &a2);
|
||||
|
||||
// XCHG is SLOW and should be avoided.
|
||||
//void XCHG(int bits, const OpArg &a1, const OpArg &a2);
|
||||
|
||||
void XCHG_AHAL();
|
||||
void BSWAP(int bits, X64Reg reg);
|
||||
void MOVSX(int dbits, int sbits, X64Reg dest, OpArg src); //auto uses MOVSXD if necessary
|
||||
void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src);
|
||||
|
||||
enum SSECompare
|
||||
{
|
||||
EQ = 0,
|
||||
LT,
|
||||
LE,
|
||||
UNORD,
|
||||
NEQ,
|
||||
NLT,
|
||||
NLE,
|
||||
ORD,
|
||||
};
|
||||
|
||||
|
||||
//SSE2
|
||||
// WARNING - These two take 11-13 cycles and are VectorPath! (AMD64)
|
||||
void STMXCSR(OpArg memloc);
|
||||
void LDMXCSR(OpArg memloc);
|
||||
|
||||
//Regular SSE instructions
|
||||
void ADDSS(X64Reg regOp, OpArg arg);
|
||||
void ADDSD(X64Reg regOp, OpArg arg);
|
||||
void SUBSS(X64Reg regOp, OpArg arg);
|
||||
void SUBSD(X64Reg regOp, OpArg arg);
|
||||
void CMPSS(X64Reg regOp, OpArg arg, u8 compare);
|
||||
void CMPSD(X64Reg regOp, OpArg arg, u8 compare);
|
||||
void ANDSS(X64Reg regOp, OpArg arg);
|
||||
void ANDSD(X64Reg regOp, OpArg arg);
|
||||
void ANDNSS(X64Reg regOp, OpArg arg);
|
||||
void ANDNSD(X64Reg regOp, OpArg arg);
|
||||
void ORSS(X64Reg regOp, OpArg arg);
|
||||
void ORSD(X64Reg regOp, OpArg arg);
|
||||
void XORSS(X64Reg regOp, OpArg arg);
|
||||
void XORSD(X64Reg regOp, OpArg arg);
|
||||
void MULSS(X64Reg regOp, OpArg arg);
|
||||
void MULSD(X64Reg regOp, OpArg arg);
|
||||
void DIVSS(X64Reg regOp, OpArg arg);
|
||||
void DIVSD(X64Reg regOp, OpArg arg);
|
||||
void MINSS(X64Reg regOp, OpArg arg);
|
||||
void MINSD(X64Reg regOp, OpArg arg);
|
||||
void MAXSS(X64Reg regOp, OpArg arg);
|
||||
void MAXSD(X64Reg regOp, OpArg arg);
|
||||
void SQRTSS(X64Reg regOp, OpArg arg);
|
||||
void SQRTSD(X64Reg regOp, OpArg arg);
|
||||
void RSQRTSS(X64Reg regOp, OpArg arg);
|
||||
void RSQRTSD(X64Reg regOp, OpArg arg);
|
||||
|
||||
void COMISS(X64Reg regOp, OpArg arg);
|
||||
void COMISD(X64Reg regOp, OpArg arg);
|
||||
|
||||
void ADDPS(X64Reg regOp, OpArg arg);
|
||||
void ADDPD(X64Reg regOp, OpArg arg);
|
||||
void SUBPS(X64Reg regOp, OpArg arg);
|
||||
void SUBPD(X64Reg regOp, OpArg arg);
|
||||
void CMPPS(X64Reg regOp, OpArg arg, u8 compare);
|
||||
void CMPPD(X64Reg regOp, OpArg arg, u8 compare);
|
||||
void ANDPS(X64Reg regOp, OpArg arg);
|
||||
void ANDPD(X64Reg regOp, OpArg arg);
|
||||
void ANDNPS(X64Reg regOp, OpArg arg);
|
||||
void ANDNPD(X64Reg regOp, OpArg arg);
|
||||
void ORPS(X64Reg regOp, OpArg arg);
|
||||
void ORPD(X64Reg regOp, OpArg arg);
|
||||
void XORPS(X64Reg regOp, OpArg arg);
|
||||
void XORPD(X64Reg regOp, OpArg arg);
|
||||
void MULPS(X64Reg regOp, OpArg arg);
|
||||
void MULPD(X64Reg regOp, OpArg arg);
|
||||
void DIVPS(X64Reg regOp, OpArg arg);
|
||||
void DIVPD(X64Reg regOp, OpArg arg);
|
||||
void MINPS(X64Reg regOp, OpArg arg);
|
||||
void MINPD(X64Reg regOp, OpArg arg);
|
||||
void MAXPS(X64Reg regOp, OpArg arg);
|
||||
void MAXPD(X64Reg regOp, OpArg arg);
|
||||
void SQRTPS(X64Reg regOp, OpArg arg);
|
||||
void SQRTPD(X64Reg regOp, OpArg arg);
|
||||
void RSQRTPS(X64Reg regOp, OpArg arg);
|
||||
void RSQRTPD(X64Reg regOp, OpArg arg);
|
||||
void SHUFPS(X64Reg regOp, OpArg arg, u8 shuffle);
|
||||
void SHUFPD(X64Reg regOp, OpArg arg, u8 shuffle);
|
||||
|
||||
void MOVDDUP(X64Reg regOp, OpArg arg);
|
||||
|
||||
void COMISS(X64Reg regOp, OpArg arg);
|
||||
void COMISD(X64Reg regOp, OpArg arg);
|
||||
void UCOMISS(X64Reg regOp, OpArg arg);
|
||||
void UCOMISD(X64Reg regOp, OpArg arg);
|
||||
|
||||
void MOVAPS(X64Reg regOp, OpArg arg);
|
||||
void MOVAPD(X64Reg regOp, OpArg arg);
|
||||
void MOVAPS(OpArg arg, X64Reg regOp);
|
||||
void MOVAPD(OpArg arg, X64Reg regOp);
|
||||
|
||||
void MOVUPS(X64Reg regOp, OpArg arg);
|
||||
void MOVUPD(X64Reg regOp, OpArg arg);
|
||||
void MOVUPS(OpArg arg, X64Reg regOp);
|
||||
void MOVUPD(OpArg arg, X64Reg regOp);
|
||||
|
||||
void MOVSS(X64Reg regOp, OpArg arg);
|
||||
void MOVSD(X64Reg regOp, OpArg arg);
|
||||
void MOVSS(OpArg arg, X64Reg regOp);
|
||||
void MOVSD(OpArg arg, X64Reg regOp);
|
||||
|
||||
void MOVMSKPS(X64Reg dest, OpArg arg);
|
||||
void MOVMSKPD(X64Reg dest, OpArg arg);
|
||||
|
||||
void MOVD_xmm(X64Reg dest, const OpArg &arg);
|
||||
void MOVQ_xmm(X64Reg dest, const OpArg &arg);
|
||||
void MOVD_xmm(const OpArg &arg, X64Reg src);
|
||||
void MOVQ_xmm(const OpArg &arg, X64Reg src);
|
||||
|
||||
void MASKMOVDQU(X64Reg dest, X64Reg src);
|
||||
void LDDQU(X64Reg dest, OpArg src);
|
||||
|
||||
void UNPCKLPD(X64Reg dest, OpArg src);
|
||||
void UNPCKHPD(X64Reg dest, OpArg src);
|
||||
|
||||
void CVTPS2PD(X64Reg dest, OpArg src);
|
||||
void CVTPD2PS(X64Reg dest, OpArg src);
|
||||
void CVTSS2SD(X64Reg dest, OpArg src);
|
||||
void CVTSD2SS(X64Reg dest, OpArg src);
|
||||
void CVTSD2SI(X64Reg dest, OpArg src);
|
||||
void CVTDQ2PD(X64Reg regOp, OpArg arg);
|
||||
void CVTPD2DQ(X64Reg regOp, OpArg arg);
|
||||
void CVTDQ2PS(X64Reg regOp, const OpArg &arg);
|
||||
|
||||
//Integer SSE instructions
|
||||
void PACKSSDW(X64Reg dest, OpArg arg);
|
||||
void PACKSSWB(X64Reg dest, OpArg arg);
|
||||
//void PACKUSDW(X64Reg dest, OpArg arg);
|
||||
void PACKUSWB(X64Reg dest, OpArg arg);
|
||||
|
||||
void PUNPCKLBW(X64Reg dest, const OpArg &arg);
|
||||
void PUNPCKLWD(X64Reg dest, const OpArg &arg);
|
||||
void PUNPCKLDQ(X64Reg dest, const OpArg &arg);
|
||||
|
||||
void PSRAD(X64Reg dest, int shift);
|
||||
|
||||
void PAND(X64Reg dest, OpArg arg);
|
||||
void PANDN(X64Reg dest, OpArg arg);
|
||||
void PXOR(X64Reg dest, OpArg arg);
|
||||
void POR(X64Reg dest, OpArg arg);
|
||||
|
||||
void PADDB(X64Reg dest, OpArg arg);
|
||||
void PADDW(X64Reg dest, OpArg arg);
|
||||
void PADDD(X64Reg dest, OpArg arg);
|
||||
void PADDQ(X64Reg dest, OpArg arg);
|
||||
|
||||
void PADDSB(X64Reg dest, OpArg arg);
|
||||
void PADDSW(X64Reg dest, OpArg arg);
|
||||
void PADDUSB(X64Reg dest, OpArg arg);
|
||||
void PADDUSW(X64Reg dest, OpArg arg);
|
||||
|
||||
void PSUBB(X64Reg dest, OpArg arg);
|
||||
void PSUBW(X64Reg dest, OpArg arg);
|
||||
void PSUBD(X64Reg dest, OpArg arg);
|
||||
void PSUBQ(X64Reg dest, OpArg arg);
|
||||
|
||||
void PSUBSB(X64Reg dest, OpArg arg);
|
||||
void PSUBSW(X64Reg dest, OpArg arg);
|
||||
void PSUBUSB(X64Reg dest, OpArg arg);
|
||||
void PSUBUSW(X64Reg dest, OpArg arg);
|
||||
|
||||
void PAVGB(X64Reg dest, OpArg arg);
|
||||
void PAVGW(X64Reg dest, OpArg arg);
|
||||
|
||||
void PCMPEQB(X64Reg dest, OpArg arg);
|
||||
void PCMPEQW(X64Reg dest, OpArg arg);
|
||||
void PCMPEQD(X64Reg dest, OpArg arg);
|
||||
|
||||
void PCMPGTB(X64Reg dest, OpArg arg);
|
||||
void PCMPGTW(X64Reg dest, OpArg arg);
|
||||
void PCMPGTD(X64Reg dest, OpArg arg);
|
||||
|
||||
void PEXTRW(X64Reg dest, OpArg arg, u8 subreg);
|
||||
void PINSRW(X64Reg dest, OpArg arg, u8 subreg);
|
||||
|
||||
void PMADDWD(X64Reg dest, OpArg arg);
|
||||
void PSADBW(X64Reg dest, OpArg arg);
|
||||
|
||||
void PMAXSW(X64Reg dest, OpArg arg);
|
||||
void PMAXUB(X64Reg dest, OpArg arg);
|
||||
void PMINSW(X64Reg dest, OpArg arg);
|
||||
void PMINUB(X64Reg dest, OpArg arg);
|
||||
|
||||
void PMOVMSKB(X64Reg dest, OpArg arg);
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
// Sets up a __cdecl function.
|
||||
// Only x64 really needs the parameter.
|
||||
void EmitPrologue(int maxCallParams);
|
||||
void EmitEpilogue(int maxCallParams);
|
||||
}
|
||||
|
||||
void CallCdeclFunction3(void* fnptr, u32 arg0, u32 arg1, u32 arg2);
|
||||
void CallCdeclFunction4(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3);
|
||||
void CallCdeclFunction5(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
|
||||
void CallCdeclFunction6(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5);
|
||||
|
||||
#if defined(_M_IX86) || !defined(_WIN32)
|
||||
|
||||
#define CallCdeclFunction3_I(a,b,c,d) CallCdeclFunction3((void *)(a), (b), (c), (d))
|
||||
#define CallCdeclFunction4_I(a,b,c,d,e) CallCdeclFunction4((void *)(a), (b), (c), (d), (e))
|
||||
#define CallCdeclFunction5_I(a,b,c,d,e,f) CallCdeclFunction5((void *)(a), (b), (c), (d), (e), (f))
|
||||
#define CallCdeclFunction6_I(a,b,c,d,e,f,g) CallCdeclFunction6((void *)(a), (b), (c), (d), (e), (f), (g))
|
||||
|
||||
#define DECLARE_IMPORT(x)
|
||||
|
||||
#else
|
||||
|
||||
// Comments from VertexLoader.cpp about these horrors:
|
||||
|
||||
// This is a horrible hack that is necessary in 64-bit mode because Opengl32.dll is based way, way above the 32-bit
|
||||
// address space that is within reach of a CALL, and just doing &fn gives us these high uncallable addresses. So we
|
||||
// want to grab the function pointers from the import table instead.
|
||||
|
||||
void ___CallCdeclImport3(void* impptr, u32 arg0, u32 arg1, u32 arg2);
|
||||
void ___CallCdeclImport4(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3);
|
||||
void ___CallCdeclImport5(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
|
||||
void ___CallCdeclImport6(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5);
|
||||
|
||||
#define CallCdeclFunction3_I(a,b,c,d) ___CallCdeclImport3(&__imp_##a,b,c,d)
|
||||
#define CallCdeclFunction4_I(a,b,c,d,e) ___CallCdeclImport4(&__imp_##a,b,c,d,e)
|
||||
#define CallCdeclFunction5_I(a,b,c,d,e,f) ___CallCdeclImport5(&__imp_##a,b,c,d,e,f)
|
||||
#define CallCdeclFunction6_I(a,b,c,d,e,f,g) ___CallCdeclImport6(&__imp_##a,b,c,d,e,f,g)
|
||||
|
||||
#define DECLARE_IMPORT(x) extern "C" void *__imp_##x
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
1237
Source/Core/Core/Core.vcproj
Normal file
1237
Source/Core/Core/Core.vcproj
Normal file
File diff suppressed because it is too large
Load Diff
603
Source/Core/Core/Src/Boot/Boot.cpp
Normal file
603
Source/Core/Core/Src/Boot/Boot.cpp
Normal file
@ -0,0 +1,603 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include "../HLE/HLE.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../PowerPC/PPCAnalyst.h"
|
||||
#include "../Core.h"
|
||||
#include "../HW/HW.h"
|
||||
#include "../HW/EXI_DeviceIPL.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "../HW/PeripheralInterface.h"
|
||||
#include "../HW/DVDInterface.h"
|
||||
#include "../HW/VideoInterface.h"
|
||||
#include "../HW/CPU.h"
|
||||
|
||||
#include "../Debugger/Debugger_SymbolMap.h"
|
||||
#include "../Debugger/Debugger_BreakPoints.h"
|
||||
|
||||
#include "Boot_DOL.h"
|
||||
#include "Boot.h"
|
||||
#include "../Host.h"
|
||||
#include "../VolumeHandler.h"
|
||||
#include "../PatchEngine.h"
|
||||
|
||||
#include "../Host.h"
|
||||
|
||||
#include "../MemTools.h"
|
||||
#include "MappedFile.h"
|
||||
|
||||
#include "VolumeCreator.h"
|
||||
|
||||
bool CBoot::Boot_BIN(const std::string& _rFilename)
|
||||
{
|
||||
Common::IMappedFile* pFile = Common::IMappedFile::CreateMappedFile();
|
||||
|
||||
if (pFile->Open(_rFilename.c_str()))
|
||||
{
|
||||
u8* pData = pFile->Lock(0, pFile->GetSize());
|
||||
Memory::WriteBigEData(pData, 0x80000000, (u32)pFile->GetSize());
|
||||
pFile->Unlock(pData);
|
||||
pFile->Close();
|
||||
}
|
||||
|
||||
delete pFile;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WrapRunFunction(void*)
|
||||
{
|
||||
while (PC != 0x00)
|
||||
{
|
||||
CCPU::SingleStep();
|
||||
}
|
||||
}
|
||||
|
||||
void WrapRunFunction2(void*)
|
||||
{
|
||||
while (PC != 0x00)
|
||||
{
|
||||
PowerPC::SingleStep();
|
||||
}
|
||||
}
|
||||
|
||||
void CBoot::RunFunction(u32 _iAddr, bool _bUseDebugger)
|
||||
{
|
||||
PC = _iAddr;
|
||||
LR = 0x00;
|
||||
|
||||
if (_bUseDebugger)
|
||||
{
|
||||
CCPU::Break();
|
||||
//EMM::Wrap(WrapRunFunction,0);
|
||||
WrapRunFunction(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
//EMM::Wrap(WrapRunFunction2,0);
|
||||
WrapRunFunction2(0);
|
||||
}
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
//
|
||||
// BIOS HLE:
|
||||
// copy the apploader to 0x81200000
|
||||
// execute the apploader
|
||||
//
|
||||
void CBoot::EmulatedBIOS(bool _bDebug)
|
||||
{
|
||||
LOG(BOOT, "Faking GC BIOS...");
|
||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||
m_MSR.FP = 1;
|
||||
|
||||
//TODO: Game iso info to 0x80000000 according to yagcd - or does apploader do this?
|
||||
|
||||
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
|
||||
//
|
||||
Memory::Write_U32(0xc2339f3d, 0x8000001C); //game disc
|
||||
Memory::Write_U32(0x0D15EA5E, 0x80000020); //funny magic word for normal boot
|
||||
Memory::Write_U32(0x01800000, 0x80000028); // Physical Memory Size
|
||||
|
||||
// Memory::Write_U32(0x00000003, 0x8000002C); // Console type - retail
|
||||
Memory::Write_U32(0x10000006, 0x8000002C); // DevKit
|
||||
|
||||
|
||||
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
|
||||
|
||||
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
||||
|
||||
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
|
||||
|
||||
// Load Apploader to Memory
|
||||
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
|
||||
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
|
||||
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
|
||||
return;
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
|
||||
|
||||
//call iAppLoaderEntry
|
||||
LOG(MASTER_LOG, "Call iAppLoaderEntry");
|
||||
|
||||
u32 iAppLoaderFuncAddr = 0x80003100;
|
||||
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
||||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||
RunFunction(iAppLoaderEntry, _bDebug);
|
||||
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
||||
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
||||
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
||||
|
||||
// iAppLoaderInit
|
||||
LOG(MASTER_LOG, "Call iAppLoaderInit");
|
||||
PowerPC::ppcState.gpr[3] = 0x81300000;
|
||||
RunFunction(iAppLoaderInit, _bDebug);
|
||||
|
||||
// iAppLoaderMain
|
||||
LOG(MASTER_LOG, "Call iAppLoaderMain");
|
||||
do
|
||||
{
|
||||
PowerPC::ppcState.gpr[3] = 0x81300004;
|
||||
PowerPC::ppcState.gpr[4] = 0x81300008;
|
||||
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
||||
|
||||
RunFunction(iAppLoaderMain, _bDebug);
|
||||
|
||||
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
||||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
|
||||
|
||||
LOG(MASTER_LOG, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
||||
|
||||
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
||||
|
||||
// iAppLoaderClose
|
||||
LOG(MASTER_LOG, "call iAppLoaderClose");
|
||||
RunFunction(iAppLoaderClose, _bDebug);
|
||||
|
||||
// Load patches and run startup patches
|
||||
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
|
||||
PatchEngine_LoadPatches(gameID.c_str());
|
||||
PatchEngine_ApplyLoadPatches();
|
||||
PowerPC::ppcState.DebugCount = 0;
|
||||
// return
|
||||
PC = PowerPC::ppcState.gpr[3];
|
||||
|
||||
//
|
||||
// --- preinit some stuff from bios ---
|
||||
//
|
||||
|
||||
|
||||
// Bus Clock Speed
|
||||
Memory::Write_U32(0x09a7ec80, 0x800000F8);
|
||||
Memory::Write_U32(0x1cf7c580, 0x800000FC);
|
||||
|
||||
// fake the VI Init of the BIOS
|
||||
Memory::Write_U32(Core::g_CoreStartupParameter.bNTSC ? 0 : 1, 0x800000CC);
|
||||
|
||||
// preset time
|
||||
Memory::Write_U32(CEXIIPL::GetGCTime(), 0x800030D8);
|
||||
}
|
||||
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
//
|
||||
// BIOS HLE:
|
||||
// copy the apploader to 0x81200000
|
||||
// execute the apploader
|
||||
//
|
||||
bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
|
||||
{
|
||||
if (!VolumeHandler::IsValid())
|
||||
{
|
||||
LOG(MASTER_LOG, "Invalid volume");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
LOG(BOOT, "Faking Wii BIOS...");
|
||||
|
||||
// load settings.txt
|
||||
{
|
||||
std::string filename;
|
||||
switch(VolumeHandler::GetVolume()->GetCountry())
|
||||
{
|
||||
case DiscIO::IVolume::COUNTRY_JAP:
|
||||
filename = "wii/setting-jpn.txt";
|
||||
break;
|
||||
|
||||
case DiscIO::IVolume::COUNTRY_USA:
|
||||
filename = "wii/setting-usa.txt";
|
||||
break;
|
||||
|
||||
default:
|
||||
filename = "wii/setting-eur.txt";
|
||||
break;
|
||||
}
|
||||
FILE* pTmp = fopen(filename.c_str(), "rb");
|
||||
if (!pTmp)
|
||||
{
|
||||
LOG(MASTER_LOG, "Cant find setting file");
|
||||
return false;
|
||||
}
|
||||
|
||||
fread(Memory::GetPointer(0x3800), 256, 1, pTmp);
|
||||
fclose(pTmp);
|
||||
}
|
||||
|
||||
// int global vars
|
||||
{
|
||||
Memory::Write_U32(0x00000000, 0x000030f0); // apploader
|
||||
Memory::Write_U16(0x0113, 0x0000315e); // apploader
|
||||
Memory::Write_U32(0x5d1c9ea3, 0x00000018); // magic word it is a wii disc
|
||||
Memory::Write_U32(0x01800000, 0x00000028);
|
||||
Memory::Write_U32(0x04000000, 0x00003118);
|
||||
Memory::Write_U32(0x00000023, 0x0000002c);
|
||||
Memory::Write_U32(0x00000000, 0x000030dc); // OSTime
|
||||
Memory::Write_U32(0x00000000, 0x000030d8); // OSTime
|
||||
Memory::Write_U32(0x00000000, 0x0000310c); // OSInit
|
||||
Memory::Write_U32(0x90000800, 0x00003124); // OSInit - MEM2 low
|
||||
Memory::Write_U32(0x933e0000, 0x00003128); // OSInit - MEM2 high
|
||||
Memory::Write_U32(0x933e0000, 0x00003130); // IPC MEM2 low
|
||||
Memory::Write_U32(0x93400000, 0x00003134); // IPC MEM2 high
|
||||
Memory::Write_U32(0x38a00040, 0x00000060); // exception init
|
||||
Memory::Write_U16(0x0000, 0x000030e6); // console type
|
||||
Memory::Write_U32(0x00000011, 0x00003138); // console type
|
||||
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // EXI
|
||||
Memory::Write_U32(0x00000000, 0x000030c0); // EXI
|
||||
Memory::Write_U32(0x00000000, 0x000030c4); // EXI
|
||||
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
|
||||
Memory::Write_U32(0x01800000, 0x00003104); // BAT
|
||||
Memory::Write_U32(0x01800000, 0x00003100); // BAT
|
||||
Memory::Write_U32(0x04000000, 0x0000311c); // BAT
|
||||
Memory::Write_U32(0x93400000, 0x00003120); // BAT
|
||||
Memory::Write_U8(0x80, 0x0000315c); // OSInit
|
||||
Memory::Write_U8(0x00, 0x00000006); // DVDInit
|
||||
Memory::Write_U8(0x00, 0x00000007); // DVDInit
|
||||
Memory::Write_U32(0x00000005, 0x000000cc); // VIInit
|
||||
Memory::Write_U16(0x0000, 0x000030e0); // PADInit
|
||||
|
||||
// app
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
|
||||
Memory::Write_U8(0x80, 0x00003184);
|
||||
}
|
||||
|
||||
// apploader
|
||||
{
|
||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||
m_MSR.FP = 1;
|
||||
|
||||
//TODO: Game iso info to 0x80000000 according to yagcd - or does apploader do this?
|
||||
|
||||
Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
|
||||
Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
|
||||
|
||||
Memory::Write_U32(((1 & 0x3f) << 26) | 2, 0x81300000); // HLE OSReport for Apploader
|
||||
|
||||
PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
|
||||
|
||||
u32 iAppLoaderOffset = 0x2440; // 0x1c40;
|
||||
|
||||
// Load Apploader to Memory
|
||||
u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
|
||||
u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
|
||||
if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
|
||||
{
|
||||
LOG(BOOT, "Invalid apploader. WTF.");
|
||||
return false;
|
||||
}
|
||||
VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
|
||||
|
||||
//call iAppLoaderEntry
|
||||
LOG(BOOT, "Call iAppLoaderEntry");
|
||||
|
||||
u32 iAppLoaderFuncAddr = 0x80004000;
|
||||
PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
|
||||
PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
|
||||
PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
|
||||
RunFunction(iAppLoaderEntry, _bDebug);
|
||||
u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
|
||||
u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
|
||||
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
|
||||
|
||||
// iAppLoaderInit
|
||||
LOG(BOOT, "Call iAppLoaderInit");
|
||||
PowerPC::ppcState.gpr[3] = 0x81300000;
|
||||
RunFunction(iAppLoaderInit, _bDebug);
|
||||
|
||||
// iAppLoaderMain
|
||||
LOG(BOOT, "Call iAppLoaderMain");
|
||||
do
|
||||
{
|
||||
PowerPC::ppcState.gpr[3] = 0x81300004;
|
||||
PowerPC::ppcState.gpr[4] = 0x81300008;
|
||||
PowerPC::ppcState.gpr[5] = 0x8130000c;
|
||||
|
||||
RunFunction(iAppLoaderMain, _bDebug);
|
||||
|
||||
u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
|
||||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
|
||||
|
||||
LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
||||
|
||||
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
||||
|
||||
// iAppLoaderClose
|
||||
LOG(BOOT, "call iAppLoaderClose");
|
||||
RunFunction(iAppLoaderClose, _bDebug);
|
||||
|
||||
// Load patches and run startup patches
|
||||
std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
|
||||
PatchEngine_LoadPatches(gameID.c_str());
|
||||
|
||||
// return
|
||||
PC = PowerPC::ppcState.gpr[3];
|
||||
}
|
||||
|
||||
PowerPC::ppcState.DebugCount = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
|
||||
{
|
||||
HLE::PatchFunctions(_gameID);
|
||||
Debugger::AnalyzeBackwards();
|
||||
Host_NotifyMapLoaded();
|
||||
Host_UpdateMemoryView();
|
||||
}
|
||||
|
||||
bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
|
||||
{
|
||||
if (_rFilename.size() == 0)
|
||||
return false;
|
||||
|
||||
std::string strDriveDirectory, strFilename;
|
||||
SplitPath(_rFilename, &strDriveDirectory, &strFilename, NULL);
|
||||
|
||||
std::string strFullfilename(strFilename + _T(".map"));
|
||||
std::string strMapFilename;
|
||||
BuildCompleteFilename(strMapFilename, strDriveDirectory, strFullfilename);
|
||||
|
||||
bool success = false;
|
||||
if (!Debugger::LoadSymbolMap(strMapFilename.c_str()))
|
||||
{
|
||||
if (_gameID != NULL)
|
||||
{
|
||||
BuildCompleteFilename(strMapFilename, _T("maps"), std::string(_gameID) + _T(".map"));
|
||||
success = Debugger::LoadSymbolMap(strMapFilename.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success)
|
||||
UpdateDebugger_MapLoaded();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
|
||||
{
|
||||
bool bResult = false;
|
||||
Common::IMappedFile* pFile = Common::IMappedFile::CreateMappedFile();
|
||||
if (pFile->Open(_rBiosFilename.c_str()))
|
||||
{
|
||||
if (pFile->GetSize() >= 1024*1024*2)
|
||||
{
|
||||
u32 CopySize = (u32)pFile->GetSize() - 0x820;
|
||||
u8* pData = pFile->Lock(0x820, CopySize);
|
||||
Memory::WriteBigEData(pData, 0x81300000, CopySize);
|
||||
pFile->Unlock(pData);
|
||||
pFile->Close();
|
||||
|
||||
PC = 0x81300000;
|
||||
|
||||
bResult = true;
|
||||
}
|
||||
}
|
||||
delete pFile;
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool CBoot::BootUp(const SCoreStartupParameter& _StartupPara)
|
||||
{
|
||||
const bool bDebugIsoBootup = false;
|
||||
|
||||
VideoInterface::PreInit(_StartupPara.bNTSC);
|
||||
switch(_StartupPara.m_BootType)
|
||||
{
|
||||
// GCM
|
||||
// ===================================================================================
|
||||
case SCoreStartupParameter::BOOT_ISO:
|
||||
{
|
||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(_StartupPara.m_strFilename);
|
||||
if (pVolume == NULL)
|
||||
break;
|
||||
|
||||
bool isoWii = DiscIO::IsVolumeWiiDisc(*pVolume);
|
||||
if (isoWii != Core::GetStartupParameter().bWii)
|
||||
{
|
||||
PanicAlert("Warning - starting ISO in wrong console mode!");
|
||||
}
|
||||
|
||||
char gameID[7];
|
||||
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
|
||||
gameID[6] = 0;
|
||||
|
||||
// setup the map from ISOFile ID
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
|
||||
|
||||
DVDInterface::SetDiscInside(true);
|
||||
|
||||
if (_StartupPara.bHLEBios)
|
||||
{
|
||||
if (!VolumeHandler::IsWii())
|
||||
EmulatedBIOS(bDebugIsoBootup);
|
||||
else
|
||||
{
|
||||
Core::g_CoreStartupParameter.bWii = true;
|
||||
EmulatedBIOS_Wii(bDebugIsoBootup);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Load_BIOS(_StartupPara.m_strBios))
|
||||
{
|
||||
// fails to load a BIOS so HLE it
|
||||
if (!VolumeHandler::IsWii())
|
||||
EmulatedBIOS(bDebugIsoBootup);
|
||||
else
|
||||
{
|
||||
Core::g_CoreStartupParameter.bWii = true;
|
||||
EmulatedBIOS_Wii(bDebugIsoBootup);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
|
||||
{
|
||||
HLE::PatchFunctions(gameID);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
//PPCAnalyst::FindFunctions(0x81300000,0x81400000);
|
||||
#if 0
|
||||
PPCAnalyst::FindFunctions(0x80003100,0x80200000);
|
||||
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
|
||||
PPCAnalyst::UseFuncDB();
|
||||
#endif
|
||||
#endif
|
||||
Debugger::GetFromAnalyzer();
|
||||
UpdateDebugger_MapLoaded();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// DOL
|
||||
// ===================================================================================
|
||||
case SCoreStartupParameter::BOOT_DOL:
|
||||
{
|
||||
CDolLoader dolLoader(_StartupPara.m_strFilename.c_str());
|
||||
PC = dolLoader.GetEntryPoint();
|
||||
#ifdef _DEBUG
|
||||
if (!LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||
{
|
||||
PPCAnalyst::FindFunctions(0x80003100,0x80400000);
|
||||
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
|
||||
PPCAnalyst::UseFuncDB();
|
||||
Debugger::GetFromAnalyzer();
|
||||
UpdateDebugger_MapLoaded();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
// ELF
|
||||
// ===================================================================================
|
||||
case SCoreStartupParameter::BOOT_ELF:
|
||||
{
|
||||
bool elfWii = IsElfWii(_StartupPara.m_strFilename.c_str());
|
||||
if (elfWii != Core::GetStartupParameter().bWii)
|
||||
{
|
||||
PanicAlert("Warning - starting ELF in wrong console mode!");
|
||||
}
|
||||
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM);
|
||||
if (elfWii)
|
||||
{
|
||||
if (VolumeHandler::IsWii() && (!_StartupPara.m_strDefaultGCM.empty()))
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
|
||||
|
||||
EmulatedBIOS_Wii(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!VolumeHandler::IsWii() && !_StartupPara.m_strDefaultGCM.empty())
|
||||
{
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
|
||||
EmulatedBIOS(false);
|
||||
}
|
||||
}
|
||||
|
||||
Boot_ELF(_StartupPara.m_strFilename.c_str());
|
||||
UpdateDebugger_MapLoaded();
|
||||
CBreakPoints::AddAutoBreakpoints();
|
||||
}
|
||||
break;
|
||||
|
||||
// BIN
|
||||
// ===================================================================================
|
||||
case SCoreStartupParameter::BOOT_BIN:
|
||||
{
|
||||
if (!_StartupPara.m_strDefaultGCM.empty())
|
||||
{
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strDefaultGCM.c_str());
|
||||
EmulatedBIOS(false);
|
||||
}
|
||||
|
||||
Boot_BIN(_StartupPara.m_strFilename);
|
||||
LoadMapFromFilename(_StartupPara.m_strFilename);
|
||||
}
|
||||
break;
|
||||
|
||||
// BIOS
|
||||
// ===================================================================================
|
||||
case SCoreStartupParameter::BOOT_BIOS:
|
||||
{
|
||||
DVDInterface::SetDiscInside(false);
|
||||
if (Load_BIOS(_StartupPara.m_strBios))
|
||||
{
|
||||
if (!LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||
{
|
||||
PPCAnalyst::FindFunctions(0x81300000,0x81400000);
|
||||
PPCAnalyst::LoadFuncDB("data/totaldb.dsy");
|
||||
PPCAnalyst::UseFuncDB();
|
||||
Debugger::GetFromAnalyzer();
|
||||
UpdateDebugger_MapLoaded();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
PanicAlert("Tried to load an unknown file type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Host_UpdateLogDisplay();
|
||||
return true;
|
||||
}
|
62
Source/Core/Core/Src/Boot/Boot.h
Normal file
62
Source/Core/Core/Src/Boot/Boot.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _BOOT_H
|
||||
#define _BOOT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include "../CoreParameter.h"
|
||||
|
||||
class CBoot
|
||||
{
|
||||
public:
|
||||
|
||||
enum TBootFileType
|
||||
{
|
||||
BOOT_ERROR,
|
||||
BOOT_DOL,
|
||||
BOOT_ELF,
|
||||
BOOT_BIN,
|
||||
BOOT_ISO,
|
||||
BOOT_BIOS
|
||||
};
|
||||
|
||||
static bool BootUp(const SCoreStartupParameter& _StartupPara);
|
||||
static bool IsElfWii(const char *filename);
|
||||
|
||||
private:
|
||||
enum { BIOS_SIZE = 2*1024*1024 };
|
||||
|
||||
static char gameID[7];
|
||||
|
||||
static void RunFunction(u32 _iAddr, bool _bUseDebugger);
|
||||
|
||||
static void UpdateDebugger_MapLoaded(const char* _gameID = NULL);
|
||||
|
||||
static bool LoadMapFromFilename(const std::string& _rFilename, const char* _gameID = NULL);
|
||||
|
||||
static bool Boot_ELF(const char *filename);
|
||||
static bool Boot_BIN(const std::string& _rFilename);
|
||||
|
||||
static void EmulatedBIOS(bool _bDebug);
|
||||
static bool EmulatedBIOS_Wii(bool _bDebug);
|
||||
static bool Load_BIOS(const std::string& _rBiosFilename);
|
||||
};
|
||||
|
||||
#endif
|
80
Source/Core/Core/Src/Boot/Boot_DOL.cpp
Normal file
80
Source/Core/Core/Src/Boot/Boot_DOL.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Boot_DOL.h"
|
||||
|
||||
#include "../HW/Memmap.h"
|
||||
|
||||
CDolLoader::CDolLoader(const char* _szFilename) : m_bInit(false)
|
||||
{
|
||||
// try to open file
|
||||
FILE* pStream = fopen(_szFilename, "rb");
|
||||
if (pStream)
|
||||
{
|
||||
fread(&m_dolheader, 1, sizeof(SDolHeader), pStream);
|
||||
|
||||
// swap memory
|
||||
u32* p = (u32*)&m_dolheader;
|
||||
for (int i=0; i<(sizeof(SDolHeader)>>2); i++)
|
||||
p[i] = Common::swap32(p[i]);
|
||||
|
||||
// load all text (code) sections
|
||||
for(int i=0; i<DOL_NUM_TEXT; i++)
|
||||
{
|
||||
if(m_dolheader.textOffset[i] != 0)
|
||||
{
|
||||
u8* pTemp = new u8[m_dolheader.textSize[i]];
|
||||
|
||||
fseek(pStream, m_dolheader.textOffset[i], SEEK_SET);
|
||||
fread(pTemp, 1, m_dolheader.textSize[i], pStream);
|
||||
|
||||
for (u32 num = 0; num < m_dolheader.textSize[i]; num++)
|
||||
Memory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num);
|
||||
|
||||
delete [] pTemp;
|
||||
}
|
||||
}
|
||||
|
||||
// load all data sections
|
||||
for(int i=0; i<DOL_NUM_DATA; i++)
|
||||
{
|
||||
if(m_dolheader.dataOffset[i] != 0)
|
||||
{
|
||||
u8* pTemp = new u8[m_dolheader.dataSize[i]];
|
||||
|
||||
fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET);
|
||||
fread(pTemp, 1, m_dolheader.dataSize[i], pStream);
|
||||
|
||||
for (u32 num = 0; num < m_dolheader.dataSize[i]; num++)
|
||||
Memory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num);
|
||||
|
||||
delete [] pTemp;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO - we know where there is code, and where there is data
|
||||
//Make use of this!
|
||||
|
||||
fclose(pStream);
|
||||
m_bInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
u32 CDolLoader::GetEntryPoint()
|
||||
{
|
||||
return m_dolheader.entryPoint;
|
||||
}
|
54
Source/Core/Core/Src/Boot/Boot_DOL.h
Normal file
54
Source/Core/Core/Src/Boot/Boot_DOL.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _BOOT_DOL_H
|
||||
#define _BOOT_DOL_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class CDolLoader
|
||||
{
|
||||
public:
|
||||
CDolLoader(const char* _szFilename);
|
||||
u32 GetEntryPoint();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
DOL_NUM_TEXT = 7,
|
||||
DOL_NUM_DATA = 11
|
||||
};
|
||||
struct SDolHeader
|
||||
{
|
||||
u32 textOffset[DOL_NUM_TEXT];
|
||||
u32 dataOffset[DOL_NUM_DATA];
|
||||
|
||||
u32 textAddress[DOL_NUM_TEXT];
|
||||
u32 dataAddress[DOL_NUM_DATA];
|
||||
|
||||
u32 textSize[DOL_NUM_TEXT];
|
||||
u32 dataSize[DOL_NUM_DATA];
|
||||
|
||||
u32 bssAddress;
|
||||
u32 bssSize;
|
||||
u32 entryPoint;
|
||||
u32 padd[7];
|
||||
};
|
||||
SDolHeader m_dolheader;
|
||||
bool m_bInit;
|
||||
};
|
||||
|
||||
#endif
|
48
Source/Core/Core/Src/Boot/Boot_ELF.cpp
Normal file
48
Source/Core/Core/Src/Boot/Boot_ELF.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "Boot.h"
|
||||
#include "Boot_ELF.h"
|
||||
#include "ElfReader.h"
|
||||
#include "MappedFile.h"
|
||||
|
||||
bool CBoot::IsElfWii(const char *filename)
|
||||
{
|
||||
Common::IMappedFile *mapfile = Common::IMappedFile::CreateMappedFile();
|
||||
mapfile->Open(filename);
|
||||
u8 *ptr = mapfile->Lock(0, mapfile->GetSize());
|
||||
u8 *mem = new u8[(size_t)mapfile->GetSize()];
|
||||
memcpy(mem, ptr, (size_t)mapfile->GetSize());
|
||||
mapfile->Unlock(ptr);
|
||||
mapfile->Close();
|
||||
|
||||
ElfReader reader(mem);
|
||||
|
||||
// TODO: Find a more reliable way to distinguish.
|
||||
bool isWii = reader.GetEntryPoint() >= 0x80004000;
|
||||
delete [] mem;
|
||||
return isWii;
|
||||
}
|
||||
|
||||
|
||||
bool CBoot::Boot_ELF(const char *filename)
|
||||
{
|
||||
Common::IMappedFile *mapfile = Common::IMappedFile::CreateMappedFile();
|
||||
mapfile->Open(filename);
|
||||
u8 *ptr = mapfile->Lock(0, mapfile->GetSize());
|
||||
u8 *mem = new u8[(size_t)mapfile->GetSize()];
|
||||
memcpy(mem, ptr, (size_t)mapfile->GetSize());
|
||||
mapfile->Unlock(ptr);
|
||||
mapfile->Close();
|
||||
|
||||
ElfReader reader(mem);
|
||||
reader.LoadInto(0x80000000);
|
||||
if (!reader.LoadSymbols())
|
||||
{
|
||||
LoadMapFromFilename(filename);
|
||||
}
|
||||
delete [] mem;
|
||||
|
||||
PC = reader.GetEntryPoint();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
1
Source/Core/Core/Src/Boot/Boot_ELF.h
Normal file
1
Source/Core/Core/Src/Boot/Boot_ELF.h
Normal file
@ -0,0 +1 @@
|
||||
#pragma once
|
266
Source/Core/Core/Src/Boot/ElfReader.cpp
Normal file
266
Source/Core/Core/Src/Boot/ElfReader.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include "../Debugger/Debugger_SymbolMap.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "ElfReader.h"
|
||||
|
||||
//#include "../PSP/HLE/sceKernelMemory.h"
|
||||
|
||||
|
||||
void bswap(Elf32_Word &w) {w = Common::swap32(w);}
|
||||
void bswap(Elf32_Half &w) {w = Common::swap16(w);}
|
||||
|
||||
|
||||
void byteswapHeader(Elf32_Ehdr &ELF_H)
|
||||
{
|
||||
bswap(ELF_H.e_type);
|
||||
bswap(ELF_H.e_machine);// = _byteswap_ushort(ELF_H.e_machine);
|
||||
bswap(ELF_H.e_ehsize);// = _byteswap_ushort(ELF_H.e_ehsize);
|
||||
bswap(ELF_H.e_phentsize);// = _byteswap_ushort(ELF_H.e_phentsize);
|
||||
bswap(ELF_H.e_phnum);// = _byteswap_ushort(ELF_H.e_phnum);
|
||||
bswap(ELF_H.e_shentsize);// = _byteswap_ushort(ELF_H.e_shentsize);
|
||||
bswap(ELF_H.e_shnum);// = _byteswap_ushort(ELF_H.e_shnum);
|
||||
bswap(ELF_H.e_shstrndx);//= _byteswap_ushort(ELF_H.e_shstrndx);
|
||||
bswap(ELF_H.e_version);// = _byteswap_ulong(ELF_H.e_version );
|
||||
bswap(ELF_H.e_entry);// = _byteswap_ulong(ELF_H.e_entry );
|
||||
bswap(ELF_H.e_phoff);// = _byteswap_ulong(ELF_H.e_phoff );
|
||||
bswap(ELF_H.e_shoff);// = _byteswap_ulong(ELF_H.e_shoff );
|
||||
bswap(ELF_H.e_flags);
|
||||
}
|
||||
|
||||
void byteswapSegment(Elf32_Phdr &sec)
|
||||
{
|
||||
bswap(sec.p_align);
|
||||
bswap(sec.p_filesz);
|
||||
bswap(sec.p_flags);
|
||||
bswap(sec.p_memsz);
|
||||
bswap(sec.p_offset);
|
||||
bswap(sec.p_paddr);
|
||||
bswap(sec.p_vaddr);
|
||||
bswap(sec.p_type);
|
||||
}
|
||||
|
||||
void byteswapSection(Elf32_Shdr &sec)
|
||||
{
|
||||
bswap(sec.sh_addr);
|
||||
bswap(sec.sh_addralign);
|
||||
bswap(sec.sh_entsize);
|
||||
bswap(sec.sh_flags);
|
||||
bswap(sec.sh_info);
|
||||
bswap(sec.sh_link);
|
||||
bswap(sec.sh_name);
|
||||
bswap(sec.sh_offset);
|
||||
bswap(sec.sh_size);
|
||||
bswap(sec.sh_type);
|
||||
}
|
||||
|
||||
|
||||
ElfReader::ElfReader(void *ptr)
|
||||
{
|
||||
base = (char*)ptr;
|
||||
base32 = (u32 *)ptr;
|
||||
header = (Elf32_Ehdr*)ptr;
|
||||
byteswapHeader(*header);
|
||||
|
||||
segments = (Elf32_Phdr *)(base + header->e_phoff);
|
||||
sections = (Elf32_Shdr *)(base + header->e_shoff);
|
||||
|
||||
for (int i = 0; i < GetNumSegments(); i++)
|
||||
{
|
||||
byteswapSegment(segments[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetNumSections(); i++)
|
||||
{
|
||||
byteswapSection(sections[i]);
|
||||
}
|
||||
entryPoint = header->e_entry;
|
||||
}
|
||||
|
||||
|
||||
const char *ElfReader::GetSectionName(int section)
|
||||
{
|
||||
if (sections[section].sh_type == SHT_NULL)
|
||||
return 0;
|
||||
|
||||
int nameOffset = sections[section].sh_name;
|
||||
char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
|
||||
|
||||
if (ptr)
|
||||
return ptr + nameOffset;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void addrToHiLo(u32 addr, u16 &hi, s16 &lo)
|
||||
{
|
||||
lo = (addr & 0xFFFF);
|
||||
u32 naddr = addr - lo;
|
||||
hi = naddr>>16;
|
||||
|
||||
u32 test = (hi<<16) + lo;
|
||||
if (test != addr)
|
||||
{
|
||||
Crash();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ElfReader::LoadInto(u32 vaddr)
|
||||
{
|
||||
LOG(MASTER_LOG,"String section: %i", header->e_shstrndx);
|
||||
|
||||
// sectionOffsets = new u32[GetNumSections()];
|
||||
// sectionAddrs = new u32[GetNumSections()];
|
||||
|
||||
// Should we relocate?
|
||||
bRelocate = (header->e_type != ET_EXEC);
|
||||
|
||||
if (bRelocate)
|
||||
{
|
||||
LOG(MASTER_LOG,"Relocatable module");
|
||||
entryPoint += vaddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(MASTER_LOG,"Prerelocated executable");
|
||||
}
|
||||
|
||||
LOG(MASTER_LOG,"%i segments:", header->e_phnum);
|
||||
|
||||
// First pass : Get the bits into RAM
|
||||
u32 segmentVAddr[32];
|
||||
|
||||
u32 baseAddress = bRelocate?vaddr:0;
|
||||
for (int i=0; i<header->e_phnum; i++)
|
||||
{
|
||||
Elf32_Phdr *p = segments + i;
|
||||
|
||||
LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz);
|
||||
|
||||
if (p->p_type == PT_LOAD)
|
||||
{
|
||||
segmentVAddr[i] = baseAddress + p->p_vaddr;
|
||||
u32 writeAddr = segmentVAddr[i];
|
||||
|
||||
u8 *src = GetSegmentPtr(i);
|
||||
u8 *dst = Memory::GetPointer(writeAddr);
|
||||
u32 srcSize = p->p_filesz;
|
||||
u32 dstSize = p->p_memsz;
|
||||
//PSPHLE::userMemory.AllocAt(writeAddr, dstSize);
|
||||
//memcpy(dst, src, srcSize);
|
||||
u32 *s = (u32*)src;
|
||||
u32 *d = (u32*)dst;
|
||||
|
||||
//TODO : remove byteswapping
|
||||
for (int i=0; i<(int)srcSize/4+1; i++)
|
||||
{
|
||||
*d++ = /*_byteswap_ulong*/(*s++);
|
||||
}
|
||||
|
||||
if (srcSize < dstSize)
|
||||
{
|
||||
//memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
|
||||
}
|
||||
|
||||
LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
LOG(MASTER_LOG,"%i sections:", header->e_shnum);
|
||||
|
||||
for (int i=0; i<GetNumSections(); i++)
|
||||
{
|
||||
Elf32_Shdr *s = §ions[i];
|
||||
const char *name = GetSectionName(i);
|
||||
|
||||
u32 writeAddr = s->sh_addr + baseAddress;
|
||||
sectionOffsets[i] = writeAddr - vaddr;
|
||||
sectionAddrs[i] = writeAddr;
|
||||
|
||||
if (s->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
LOG(MASTER_LOG,"Data Section found: %s Sitting at %08x, size %08x", name, writeAddr, s->sh_size);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(MASTER_LOG,"NonData Section found: %s Ignoring (size=%08x) (flags=%08x)", name, s->sh_size, s->sh_flags);
|
||||
}
|
||||
}
|
||||
*/
|
||||
LOG(MASTER_LOG,"Done.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SectionID ElfReader::GetSectionByName(const char *name, int firstSection)
|
||||
{
|
||||
for (int i = firstSection; i < header->e_shnum; i++)
|
||||
{
|
||||
const char *secname = GetSectionName(i);
|
||||
|
||||
if (secname != 0 && strcmp(name, secname) == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ElfReader::LoadSymbols()
|
||||
{
|
||||
bool hasSymbols = false;
|
||||
SectionID sec = GetSectionByName(".symtab");
|
||||
if (sec != -1)
|
||||
{
|
||||
int stringSection = sections[sec].sh_link;
|
||||
|
||||
const char *stringBase = (const char*)GetSectionDataPtr(stringSection);
|
||||
|
||||
//We have a symbol table!
|
||||
Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
|
||||
|
||||
int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
|
||||
|
||||
for (int sym = 0; sym<numSymbols; sym++)
|
||||
{
|
||||
int size = Common::swap32(symtab[sym].st_size);
|
||||
if (size == 0)
|
||||
continue;
|
||||
|
||||
// int bind = symtab[sym].st_info >> 4;
|
||||
int type = symtab[sym].st_info & 0xF;
|
||||
int sectionIndex = Common::swap16(symtab[sym].st_shndx);
|
||||
int value = Common::swap32(symtab[sym].st_value);
|
||||
const char *name = stringBase + Common::swap32(symtab[sym].st_name);
|
||||
|
||||
if (bRelocate)
|
||||
value += sectionAddrs[sectionIndex];
|
||||
|
||||
Debugger::ESymbolType symtype = Debugger::ST_DATA;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case STT_OBJECT:
|
||||
symtype = Debugger::ST_DATA; break;
|
||||
case STT_FUNC:
|
||||
symtype =Debugger:: ST_FUNCTION; break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
//host->AddSymbol(name, value, size, symtype);
|
||||
Debugger::AddSymbol(
|
||||
Debugger::CSymbol(value, size, symtype, name));
|
||||
|
||||
hasSymbols = true;
|
||||
//...
|
||||
}
|
||||
}
|
||||
return hasSymbols;
|
||||
}
|
||||
|
85
Source/Core/Core/Src/Boot/ElfReader.h
Normal file
85
Source/Core/Core/Src/Boot/ElfReader.h
Normal file
@ -0,0 +1,85 @@
|
||||
#ifndef _ELFREADER_H
|
||||
#define _ELFREADER_H
|
||||
|
||||
#include "ElfTypes.h"
|
||||
|
||||
enum KnownElfTypes
|
||||
{
|
||||
KNOWNELF_PSP = 0,
|
||||
KNOWNELF_DS = 1,
|
||||
KNOWNELF_GBA = 2,
|
||||
KNOWNELF_GC = 3,
|
||||
};
|
||||
|
||||
typedef int SectionID;
|
||||
|
||||
class ElfReader
|
||||
{
|
||||
char *base;
|
||||
u32 *base32;
|
||||
|
||||
Elf32_Ehdr *header;
|
||||
Elf32_Phdr *segments;
|
||||
Elf32_Shdr *sections;
|
||||
|
||||
u32 *sectionOffsets;
|
||||
u32 *sectionAddrs;
|
||||
bool bRelocate;
|
||||
u32 entryPoint;
|
||||
|
||||
public:
|
||||
ElfReader(void *ptr);
|
||||
|
||||
~ElfReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
u32 Read32(int off)
|
||||
{
|
||||
return base32[off>>2];
|
||||
}
|
||||
|
||||
// Quick accessors
|
||||
ElfType GetType() { return (ElfType)(header->e_type); }
|
||||
ElfMachine GetMachine() { return (ElfMachine)(header->e_machine); }
|
||||
u32 GetEntryPoint() { return entryPoint; }
|
||||
u32 GetFlags() { return (u32)(header->e_flags); }
|
||||
|
||||
int GetNumSegments() { return (int)(header->e_phnum); }
|
||||
int GetNumSections() { return (int)(header->e_shnum); }
|
||||
const char *GetSectionName(int section);
|
||||
u8 *GetPtr(int offset)
|
||||
{
|
||||
return (u8*)base + offset;
|
||||
}
|
||||
u8 *GetSectionDataPtr(int section)
|
||||
{
|
||||
if (section < 0 || section >= header->e_shnum)
|
||||
return 0;
|
||||
if (sections[section].sh_type != SHT_NOBITS)
|
||||
return GetPtr(sections[section].sh_offset);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
u8 *GetSegmentPtr(int segment)
|
||||
{
|
||||
return GetPtr(segments[segment].p_offset);
|
||||
}
|
||||
u32 GetSectionAddr(SectionID section) {return sectionAddrs[section];}
|
||||
int GetSectionSize(SectionID section)
|
||||
{
|
||||
return sections[section].sh_size;
|
||||
}
|
||||
SectionID GetSectionByName(const char *name, int firstSection=0); //-1 for not found
|
||||
|
||||
bool DidRelocate() {
|
||||
return bRelocate;
|
||||
}
|
||||
// More indepth stuff:)
|
||||
bool LoadInto(u32 vaddr);
|
||||
bool LoadSymbols();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
281
Source/Core/Core/Src/Boot/ElfTypes.h
Normal file
281
Source/Core/Core/Src/Boot/ElfTypes.h
Normal file
@ -0,0 +1,281 @@
|
||||
#ifndef _ELFTYPES_H
|
||||
#define _ELFTYPES_H
|
||||
|
||||
// ELF Header Constants
|
||||
|
||||
// File type
|
||||
enum ElfType
|
||||
{
|
||||
ET_NONE =0,
|
||||
ET_REL =1,
|
||||
ET_EXEC =2,
|
||||
ET_DYN =3,
|
||||
ET_CORE =4,
|
||||
ET_LOPROC =0xFF00,
|
||||
ET_HIPROC =0xFFFF,
|
||||
};
|
||||
|
||||
// Machine/Architecture
|
||||
enum ElfMachine
|
||||
{
|
||||
EM_NONE =0,
|
||||
EM_M32 =1,
|
||||
EM_SPARC =2,
|
||||
EM_386 =3,
|
||||
EM_68K =4,
|
||||
EM_88K =5,
|
||||
EM_860 =7,
|
||||
EM_MIPS =8
|
||||
};
|
||||
|
||||
// File version
|
||||
#define EV_NONE 0
|
||||
#define EV_CURRENT 1
|
||||
|
||||
// Identification index
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
#define EI_PAD 7
|
||||
#define EI_NIDENT 16
|
||||
|
||||
// Magic number
|
||||
#define ELFMAG0 0x7F
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
|
||||
// File class
|
||||
#define ELFCLASSNONE 0
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
|
||||
// Encoding
|
||||
#define ELFDATANONE 0
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Sections constants
|
||||
|
||||
// Section indexes
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_LORESERVE 0xFF00
|
||||
#define SHN_LOPROC 0xFF00
|
||||
#define SHN_HIPROC 0xFF1F
|
||||
#define SHN_ABS 0xFFF1
|
||||
#define SHN_COMMON 0xFFF2
|
||||
#define SHN_HIRESERVE 0xFFFF
|
||||
|
||||
// Section types
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
#define SHT_LOPROC 0x70000000
|
||||
#define SHT_HIPROC 0x7FFFFFFF
|
||||
#define SHT_LOUSER 0x80000000
|
||||
#define SHT_HIUSER 0xFFFFFFFF
|
||||
|
||||
// Custom section types
|
||||
#define SHT_PSPREL 0x700000a0
|
||||
|
||||
|
||||
// Section flags
|
||||
enum ElfSectionFlags
|
||||
{
|
||||
SHF_WRITE =0x1,
|
||||
SHF_ALLOC =0x2,
|
||||
SHF_EXECINSTR =0x4,
|
||||
SHF_MASKPROC =0xF0000000,
|
||||
};
|
||||
|
||||
// Symbol binding
|
||||
#define STB_LOCAL 0
|
||||
#define STB_GLOBAL 1
|
||||
#define STB_WEAK 2
|
||||
#define STB_LOPROC 13
|
||||
#define STB_HIPROC 15
|
||||
|
||||
// Symbol types
|
||||
#define STT_NOTYPE 0
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
#define STT_SECTION 3
|
||||
#define STT_FILE 4
|
||||
#define STT_LOPROC 13
|
||||
#define STT_HIPROC 15
|
||||
|
||||
// Undefined name
|
||||
#define STN_UNDEF 0
|
||||
|
||||
// Relocation types
|
||||
#define R_386_NONE 0
|
||||
#define R_386_32 1
|
||||
#define R_386_PC32 2
|
||||
#define R_386_GOT32 3
|
||||
#define R_386_PLT32 4
|
||||
#define R_386_COPY 5
|
||||
#define R_386_GLOB_DAT 6
|
||||
#define R_386_JMP_SLOT 7
|
||||
#define R_386_RELATIVE 8
|
||||
#define R_386_GOTOFF 9
|
||||
#define R_386_GOTPC 10
|
||||
|
||||
// Segment types
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7FFFFFFF
|
||||
|
||||
// Segment flags
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
|
||||
// Dynamic Array Tags
|
||||
#define DT_NULL 0
|
||||
#define DT_NEEDED 1
|
||||
#define DT_PLTRELSZ 2
|
||||
#define DT_PLTGOT 3
|
||||
#define DT_HASH 4
|
||||
#define DT_STRTAB 5
|
||||
#define DT_SYMTAB 6
|
||||
#define DT_RELA 7
|
||||
#define DT_RELASZ 8
|
||||
#define DT_RELAENT 9
|
||||
#define DT_STRSZ 10
|
||||
#define DT_SYMENT 11
|
||||
#define DT_INIT 12
|
||||
#define DT_FINI 13
|
||||
#define DT_SONAME 14
|
||||
#define DT_RPATH 15
|
||||
#define DT_SYMBOLIC 16
|
||||
#define DT_REL 17
|
||||
#define DT_RELSZ 18
|
||||
#define DT_RELENT 19
|
||||
#define DT_PLTREL 20
|
||||
#define DT_DEBUG 21
|
||||
#define DT_TEXTREL 22
|
||||
#define DT_JMPREL 23
|
||||
#define DT_LOPROC 0x70000000
|
||||
#define DT_HIPROC 0x7FFFFFFF
|
||||
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef signed int Elf32_Sword;
|
||||
typedef unsigned int Elf32_Word;
|
||||
|
||||
|
||||
// ELF file header
|
||||
struct Elf32_Ehdr
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
};
|
||||
|
||||
// Section header
|
||||
struct Elf32_Shdr
|
||||
{
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
};
|
||||
|
||||
// Segment header
|
||||
struct Elf32_Phdr
|
||||
{
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
};
|
||||
|
||||
// Symbol table entry
|
||||
struct Elf32_Sym
|
||||
{
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
};
|
||||
|
||||
#define ELF32_ST_BIND(i) ((i)>>4)
|
||||
#define ELF32_ST_TYPE(i) ((i)&0xf)
|
||||
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
|
||||
|
||||
// Relocation entries
|
||||
struct Elf32_Rel
|
||||
{
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
};
|
||||
|
||||
struct Elf32_Rela
|
||||
{
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
Elf32_Sword r_addend;
|
||||
};
|
||||
|
||||
#define ELF32_R_SYM(i) ((i)>>8)
|
||||
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||
#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t))
|
||||
|
||||
|
||||
struct Elf32_Dyn
|
||||
{
|
||||
Elf32_Sword d_tag;
|
||||
union
|
||||
{
|
||||
Elf32_Word d_val;
|
||||
Elf32_Addr d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
176
Source/Core/Core/Src/Console.cpp
Normal file
176
Source/Core/Core/Src/Console.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include <iostream>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "Thread.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "PowerPC/PPCAnalyst.h"
|
||||
#include "PowerPC/PPCTables.h"
|
||||
#include "Console.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "Core.h"
|
||||
#include "PowerPC/Jit64/JitCache.h"
|
||||
#include "PowerPCDisasm.h"
|
||||
|
||||
#define CASE(x) else if (memcmp(cmd, x,4*sizeof(TCHAR))==0)
|
||||
#define CASE1(x) if (memcmp(cmd, x,2*sizeof(TCHAR))==0)
|
||||
|
||||
Common::Thread *cons_thread;
|
||||
/*
|
||||
THREAD_RETURN ConsoleThreadFunc(void *) {
|
||||
printf("Welcome to the console thread!\n\n");
|
||||
while (true) {
|
||||
std::string command;
|
||||
getline(std::cin, command);
|
||||
Console_Submit(command.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void StartConsoleThread() {
|
||||
cons_thread = new Common::Thread(ConsoleThreadFunc, 0);
|
||||
}*/
|
||||
|
||||
void Console_Submit(const char *cmd)
|
||||
{
|
||||
CASE1("jits")
|
||||
{
|
||||
#ifdef _M_X64
|
||||
Jit64::PrintStats();
|
||||
#endif
|
||||
}
|
||||
CASE1("r")
|
||||
{
|
||||
Core::StartTrace(false);
|
||||
LOG(CONSOLE, "read tracing started.");
|
||||
}
|
||||
CASE1("w")
|
||||
{
|
||||
Core::StartTrace(true);
|
||||
LOG(CONSOLE, "write tracing started.");
|
||||
}
|
||||
CASE("scan")
|
||||
{
|
||||
//LOG(CONSOLE,"test1");
|
||||
PPCAnalyst::FindFunctions(0x80003100, 0x80400000);
|
||||
}
|
||||
CASE("trans")
|
||||
{
|
||||
TCHAR temp[256];
|
||||
u32 addr;
|
||||
sscanf(cmd, "%s %08x", temp, &addr);
|
||||
|
||||
if (addr!=0)
|
||||
{
|
||||
u32 EA = Memory::CheckDTLB(addr, Memory::FLAG_NO_EXCEPTION);
|
||||
LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(CONSOLE, "Syntax: trans ADDR");
|
||||
}
|
||||
}
|
||||
CASE("call")
|
||||
{
|
||||
TCHAR temp[256];
|
||||
u32 addr;
|
||||
sscanf(cmd, "%s %08x", temp, &addr);
|
||||
if (addr!=0)
|
||||
{
|
||||
PPCAnalyst::PrintCalls(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(CONSOLE, "Syntax: call ADDR");
|
||||
}
|
||||
}
|
||||
CASE("llac")
|
||||
{
|
||||
TCHAR temp[256];
|
||||
u32 addr;
|
||||
sscanf(cmd, "%s %08x", temp, &addr);
|
||||
if (addr!=0)
|
||||
{
|
||||
PPCAnalyst::PrintCallers(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(CONSOLE, "Syntax: llac ADDR");
|
||||
}
|
||||
}
|
||||
CASE("pend")
|
||||
{
|
||||
CoreTiming::LogPendingEvents();
|
||||
}
|
||||
CASE("dump")
|
||||
{
|
||||
TCHAR temp[256];
|
||||
TCHAR filename[256];
|
||||
u32 start;
|
||||
u32 end;
|
||||
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
|
||||
|
||||
FILE *f = fopen(filename, "wb");
|
||||
for (u32 i=start; i<end; i++)
|
||||
{
|
||||
u8 b = Memory::ReadUnchecked_U8(i);
|
||||
fputc(b,f);
|
||||
}
|
||||
fclose(f);
|
||||
LOG(CONSOLE, "Dumped from %08x to %08x to %s",start,end,filename);
|
||||
}
|
||||
CASE("disa")
|
||||
{
|
||||
u32 start;
|
||||
u32 end;
|
||||
TCHAR temp[256];
|
||||
sscanf(cmd, "%s %08x %08x", temp, &start, &end);
|
||||
for (u32 addr = start; addr <= end; addr += 4) {
|
||||
u32 data = Memory::ReadUnchecked_U32(addr);
|
||||
printf("%08x: %08x: %s\n", addr, data, DisassembleGekko(data, addr));
|
||||
}
|
||||
}
|
||||
CASE("help")
|
||||
{
|
||||
LOG(CONSOLE, "Dolphin Console Command List");
|
||||
LOG(CONSOLE, "scan ADDR - will find functions that are called by this function");
|
||||
LOG(CONSOLE, "call ADDR - will find functions that call this function");
|
||||
LOG(CONSOLE, "dump START_A END_A FILENAME - will dump memory between START_A and END_A");
|
||||
LOG(CONSOLE, "help - guess what this does :P");
|
||||
LOG(CONSOLE, "lisd - list signature database");
|
||||
LOG(CONSOLE, "lisf - list functions");
|
||||
LOG(CONSOLE, "trans ADDR - translate address");
|
||||
}
|
||||
CASE("lisd")
|
||||
{
|
||||
PPCAnalyst::ListDB();
|
||||
}
|
||||
CASE("ipro")
|
||||
{
|
||||
PPCTables::PrintInstructionRunCounts();
|
||||
}
|
||||
CASE("lisf")
|
||||
{
|
||||
PPCAnalyst::ListFunctions();
|
||||
}
|
||||
else {
|
||||
printf("blach\n");
|
||||
LOG(CONSOLE, "Invalid command");
|
||||
}
|
||||
}
|
24
Source/Core/Core/Src/Console.h
Normal file
24
Source/Core/Core/Src/Console.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _CONSOLE_H
|
||||
#define _CONSOLE_H
|
||||
|
||||
void Console_Submit(const char *cmd);
|
||||
// void StartConsoleThread();
|
||||
|
||||
#endif
|
||||
|
496
Source/Core/Core/Src/Core.cpp
Normal file
496
Source/Core/Core/Src/Core.cpp
Normal file
@ -0,0 +1,496 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Timer.H"
|
||||
|
||||
#include "Console.h"
|
||||
#include "Core.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "Boot/Boot.h"
|
||||
#include "PatchEngine.h"
|
||||
|
||||
#include "HW/Memmap.h"
|
||||
#include "HW/PeripheralInterface.h"
|
||||
#include "HW/GPFifo.h"
|
||||
#include "HW/CPU.h"
|
||||
#include "HW/CPUCompare.h"
|
||||
#include "HW/HW.h"
|
||||
#include "HW/DSP.h"
|
||||
#include "HW/GPFifo.h"
|
||||
#include "HW/AudioInterface.h"
|
||||
#include "HW/VideoInterface.h"
|
||||
#include "HW/CommandProcessor.h"
|
||||
#include "HW/PixelEngine.h"
|
||||
#include "HW/SystemTimers.h"
|
||||
|
||||
#include "PowerPC/PowerPC.h"
|
||||
|
||||
#include "Plugins/Plugin_Video.h"
|
||||
#include "Plugins/Plugin_PAD.h"
|
||||
#include "Plugins/Plugin_DSP.h"
|
||||
|
||||
#include "MemTools.h"
|
||||
#include "Host.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#define WINAPI
|
||||
#endif
|
||||
|
||||
// The idea behind the recent restructure is to fix various stupid problems.
|
||||
// glXMakeCurrent/ wglMakeCurrent takes a context and makes it current on the current thread.
|
||||
// So it's fine to init ogl on one thread, and then make it current and start blasting on another.
|
||||
|
||||
namespace Core
|
||||
{
|
||||
// forwarding
|
||||
//void Callback_VideoRequestWindowSize(int _iWidth, int _iHeight, BOOL _bFullscreen);
|
||||
void Callback_VideoLog(const TCHAR* _szMessage, BOOL _bDoBreak);
|
||||
void Callback_VideoCopiedToXFB();
|
||||
void Callback_DSPLog(const TCHAR* _szMessage);
|
||||
void Callback_DSPInterrupt();
|
||||
void Callback_DVDLog(const TCHAR* _szMessage);
|
||||
void Callback_DVDSetStatusbar(TCHAR* _szMessage);
|
||||
void Callback_PADLog(const TCHAR* _szMessage);
|
||||
TPeekMessages Callback_PeekMessages = NULL;
|
||||
TUpdateFPSDisplay g_pUpdateFPSDisplay = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI EmuThread(void *pArg);
|
||||
#else
|
||||
void *EmuThread(void *pArg);
|
||||
#endif
|
||||
void Stop();
|
||||
|
||||
bool g_bHwInit = false;
|
||||
HWND g_pWindowHandle = NULL;
|
||||
Common::Thread* g_pThread = NULL;
|
||||
|
||||
SCoreStartupParameter g_CoreStartupParameter; //uck
|
||||
|
||||
Common::Event emuThreadGoing;
|
||||
|
||||
// Called from GUI thread
|
||||
bool Init(const SCoreStartupParameter _CoreParameter)
|
||||
{
|
||||
if (g_pThread != NULL)
|
||||
return false;
|
||||
|
||||
LogManager::Init();
|
||||
Host_SetWaitCursor(true);
|
||||
|
||||
g_CoreStartupParameter = _CoreParameter;
|
||||
// Init the Hardware
|
||||
|
||||
// start the thread again
|
||||
_dbg_assert_(HLE, g_pThread == NULL);
|
||||
|
||||
// load plugins
|
||||
if (!PluginDSP::LoadPlugin(g_CoreStartupParameter.m_strDSPPlugin.c_str())) {
|
||||
PanicAlert("Failed to load DSP plugin %s", g_CoreStartupParameter.m_strDSPPlugin.c_str());
|
||||
return false;
|
||||
}
|
||||
if (!PluginPAD::LoadPlugin(g_CoreStartupParameter.m_strPadPlugin.c_str())) {
|
||||
PanicAlert("Failed to load PAD plugin %s", g_CoreStartupParameter.m_strPadPlugin.c_str());
|
||||
return false;
|
||||
}
|
||||
if (!PluginVideo::LoadPlugin(g_CoreStartupParameter.m_strVideoPlugin.c_str())) {
|
||||
PanicAlert("Failed to load video plugin %s", g_CoreStartupParameter.m_strVideoPlugin.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
PluginDSP::DllDebugger((HWND)_CoreParameter.hMainWindow);
|
||||
#endif
|
||||
|
||||
emuThreadGoing.Init();
|
||||
|
||||
g_pThread = new Common::Thread(EmuThread, (void*)&g_CoreStartupParameter);
|
||||
|
||||
emuThreadGoing.Wait();
|
||||
emuThreadGoing.Shutdown();
|
||||
// all right ... here we go
|
||||
Host_SetWaitCursor(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called from GUI thread or VI thread
|
||||
void Stop() // - Hammertime!
|
||||
{
|
||||
Host_SetWaitCursor(true);
|
||||
if (PowerPC::state == PowerPC::CPU_POWERDOWN)
|
||||
return;
|
||||
// stop the CPU
|
||||
PowerPC::state = PowerPC::CPU_POWERDOWN;
|
||||
|
||||
CCPU::StepOpcode(); //kick it if it's waiting
|
||||
|
||||
// The quit is to get it out of its message loop
|
||||
// Should be moved inside the plugin.
|
||||
#ifdef _WIN32
|
||||
PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
|
||||
#else
|
||||
// TODO(ector) : post message exit
|
||||
#endif
|
||||
|
||||
delete g_pThread; //Wait for emuthread to close
|
||||
Core::StopTrace();
|
||||
LogManager::Shutdown();
|
||||
g_pThread = 0;
|
||||
Host_SetWaitCursor(false);
|
||||
}
|
||||
|
||||
THREAD_RETURN CpuThread(void *pArg)
|
||||
{
|
||||
Common::SetCurrentThreadName("CPU thread");
|
||||
|
||||
const SCoreStartupParameter& _CoreParameter = g_CoreStartupParameter;
|
||||
if (!g_CoreStartupParameter.bUseDualCore)
|
||||
{
|
||||
PluginVideo::Video_Prepare(); //wglMakeCurrent
|
||||
}
|
||||
|
||||
if (_CoreParameter.bRunCompareServer)
|
||||
{
|
||||
CPUCompare::StartServer();
|
||||
PowerPC::state = PowerPC::CPU_RUNNING;
|
||||
}
|
||||
else if (_CoreParameter.bRunCompareClient)
|
||||
{
|
||||
PanicAlert("Compare Debug : Press OK when ready.");
|
||||
CPUCompare::ConnectAsClient();
|
||||
}
|
||||
|
||||
Common::Thread::SetCurrentThreadAffinity(1); //Force to first core
|
||||
|
||||
// Let's run under memory watch
|
||||
EMM::InstallExceptionHandler();
|
||||
// StartConsoleThread();
|
||||
CCPU::Run();
|
||||
|
||||
if (_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
|
||||
{
|
||||
CPUCompare::Stop();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Callback_DebuggerBreak()
|
||||
{
|
||||
CCPU::EnableStepping(true);
|
||||
}
|
||||
|
||||
THREAD_RETURN EmuThread(void *pArg)
|
||||
{
|
||||
Host_BootingStarted();
|
||||
|
||||
Common::SetCurrentThreadName("Emuthread - starting");
|
||||
const SCoreStartupParameter& _CoreParameter = *(SCoreStartupParameter*)pArg;
|
||||
|
||||
Common::Thread::SetCurrentThreadAffinity(2); //Force to second core
|
||||
|
||||
LOG(OSREPORT, "Starting core = %s mode", _CoreParameter.bWii ? "Wii" : "Gamecube");
|
||||
LOG(OSREPORT, "Dualcore = %s", _CoreParameter.bUseDualCore ? "Yes" : "No");
|
||||
|
||||
HW::Init();
|
||||
|
||||
emuThreadGoing.Set();
|
||||
|
||||
// Load the VideoPlugin
|
||||
SVideoInitialize VideoInitialize;
|
||||
VideoInitialize.pGetMemoryPointer = Memory::GetPointer;
|
||||
VideoInitialize.pSetPEToken = PixelEngine::SetToken;
|
||||
VideoInitialize.pSetPEFinish = PixelEngine::SetFinish;
|
||||
VideoInitialize.pWindowHandle = NULL; //_CoreParameter.hMainWindow; // NULL; // filled by video_initialize
|
||||
VideoInitialize.pLog = Callback_VideoLog;
|
||||
VideoInitialize.pRequestWindowSize = NULL; //Callback_VideoRequestWindowSize;
|
||||
VideoInitialize.pCopiedToXFB = Callback_VideoCopiedToXFB;
|
||||
VideoInitialize.pVIRegs = VideoInterface::m_UVIUnknownRegs;
|
||||
VideoInitialize.pPeekMessages = NULL;
|
||||
VideoInitialize.pUpdateFPSDisplay = NULL;
|
||||
VideoInitialize.pCPFifo = (SCPFifoStruct*)&CommandProcessor::fifo;
|
||||
VideoInitialize.pUpdateInterrupts = &(CommandProcessor::UpdateInterruptsFromVideoPlugin);
|
||||
VideoInitialize.pMemoryBase = Memory::base;
|
||||
PluginVideo::Video_Initialize(&VideoInitialize);
|
||||
|
||||
// Under linux, this is an X11 Display, not an HWND!
|
||||
g_pWindowHandle = (HWND)VideoInitialize.pWindowHandle;
|
||||
Callback_PeekMessages = VideoInitialize.pPeekMessages;
|
||||
g_pUpdateFPSDisplay = VideoInitialize.pUpdateFPSDisplay;
|
||||
|
||||
// Load and init DSPPlugin
|
||||
DSPInitialize dspInit;
|
||||
dspInit.hWnd = g_pWindowHandle;
|
||||
dspInit.pARAM_Read_U8 = (u8 (__cdecl *)(const u32))DSP::ReadARAM;
|
||||
dspInit.pGetARAMPointer = DSP::GetARAMPtr;
|
||||
dspInit.pGetMemoryPointer = Memory::GetPointer;
|
||||
dspInit.pLog = Callback_DSPLog;
|
||||
dspInit.pDebuggerBreak = Callback_DebuggerBreak;
|
||||
dspInit.pGenerateDSPInterrupt = Callback_DSPInterrupt;
|
||||
dspInit.pGetAudioStreaming = AudioInterface::Callback_GetStreaming;
|
||||
PluginDSP::DSP_Initialize(dspInit);
|
||||
|
||||
// Load and Init PadPlugin
|
||||
SPADInitialize PADInitialize;
|
||||
PADInitialize.hWnd = g_pWindowHandle;
|
||||
PADInitialize.pLog = Callback_PADLog;
|
||||
PluginPAD::PAD_Initialize(PADInitialize);
|
||||
|
||||
// The hardware is initialized.
|
||||
g_bHwInit = true;
|
||||
|
||||
// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
|
||||
PowerPC::SetCore(PowerPC::CORE_INTERPRETER);
|
||||
CBoot::BootUp(_CoreParameter);
|
||||
|
||||
if( g_pUpdateFPSDisplay != NULL )
|
||||
g_pUpdateFPSDisplay("Loading...");
|
||||
|
||||
// setup our core, but can't use dynarec if we are compare server
|
||||
if (_CoreParameter.bUseDynarec && !_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
|
||||
PowerPC::SetCore(PowerPC::CORE_DYNAREC);
|
||||
else
|
||||
PowerPC::SetCore(PowerPC::CORE_INTERPRETER);
|
||||
|
||||
// update the window again because all stuff is initialized
|
||||
Host_UpdateDisasmDialog();
|
||||
Host_UpdateMainFrame();
|
||||
Host_BootingEnded();
|
||||
|
||||
//This thread, after creating the EmuWindow, spawns a CPU thread,
|
||||
//then takes over and becomes the graphics thread
|
||||
|
||||
//In single core mode, the CPU thread does the graphics. In fact, the
|
||||
//CPU thread should in this case also create the emuwindow...
|
||||
|
||||
//Spawn the CPU thread
|
||||
Common::Thread *cpuThread = new Common::Thread(CpuThread, pArg);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ENTER THE VIDEO THREAD LOOP
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (!Core::GetStartupParameter().bUseDualCore)
|
||||
{
|
||||
Common::SetCurrentThreadName("Idle thread");
|
||||
//TODO(ector) : investigate using GetMessage instead .. although
|
||||
//then we lose the powerdown check. ... unless powerdown sends a message :P
|
||||
while (PowerPC::state != PowerPC::CPU_POWERDOWN)
|
||||
{
|
||||
if (Callback_PeekMessages) {
|
||||
Callback_PeekMessages();
|
||||
}
|
||||
Common::SleepCurrentThread(20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginVideo::Video_Prepare(); //wglMakeCurrent
|
||||
Common::SetCurrentThreadName("Video thread");
|
||||
PluginVideo::Video_EnterLoop();
|
||||
}
|
||||
|
||||
// Wait for CPU thread to exit - it should have been signaled to do so by now
|
||||
if( g_pUpdateFPSDisplay != NULL )
|
||||
g_pUpdateFPSDisplay("Stopping...");
|
||||
delete cpuThread;
|
||||
// Returns after game exited
|
||||
|
||||
g_bHwInit = false;
|
||||
|
||||
PluginPAD::PAD_Shutdown();
|
||||
PluginPAD::UnloadPlugin();
|
||||
PluginDSP::DSP_Shutdown();
|
||||
PluginDSP::UnloadPlugin();
|
||||
PluginVideo::Video_Shutdown();
|
||||
PluginVideo::UnloadPlugin();
|
||||
|
||||
HW::Shutdown();
|
||||
|
||||
LOG(MASTER_LOG,"EmuThread exited");
|
||||
//The CPU should return when a game is stopped and cleanup should be done here,
|
||||
//so we can restart the plugins (or load new ones) for the next game
|
||||
|
||||
Host_UpdateMainFrame();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SetState(EState _State)
|
||||
{
|
||||
switch(_State)
|
||||
{
|
||||
case CORE_UNINITIALIZED:
|
||||
Stop();
|
||||
break;
|
||||
|
||||
case CORE_PAUSE:
|
||||
CCPU::EnableStepping(true);
|
||||
break;
|
||||
|
||||
case CORE_RUN:
|
||||
CCPU::EnableStepping(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EState GetState()
|
||||
{
|
||||
if (g_bHwInit)
|
||||
{
|
||||
if (CCPU::IsStepping())
|
||||
return CORE_PAUSE;
|
||||
else
|
||||
return CORE_RUN;
|
||||
}
|
||||
return CORE_UNINITIALIZED;
|
||||
}
|
||||
|
||||
const SCoreStartupParameter& GetStartupParameter()
|
||||
{
|
||||
return g_CoreStartupParameter;
|
||||
}
|
||||
|
||||
bool MakeScreenshot(const std::string& _rFilename)
|
||||
{
|
||||
bool bResult = false;
|
||||
if (PluginVideo::IsLoaded())
|
||||
{
|
||||
TCHAR szTmpFilename[MAX_PATH];
|
||||
strcpy(szTmpFilename, _rFilename.c_str());
|
||||
bResult = PluginVideo::Video_Screenshot(szTmpFilename);
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void* GetWindowHandle()
|
||||
{
|
||||
return g_pWindowHandle;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --- Callbacks for plugins / engine ---
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_VideoLog
|
||||
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
|
||||
void Callback_VideoLog(const TCHAR *_szMessage, BOOL _bDoBreak)
|
||||
{
|
||||
LOG(VIDEO, _szMessage);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_VideoCopiedToXFB
|
||||
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
|
||||
// We do not touch anything outside this function here
|
||||
void Callback_VideoCopiedToXFB()
|
||||
{
|
||||
//count FPS
|
||||
static Common::Timer Timer;
|
||||
static u32 frames = 0;
|
||||
static u64 ticks = 0;
|
||||
static u64 idleTicks = 0;
|
||||
frames++;
|
||||
|
||||
if (Timer.GetTimeDifference() >= 1000)
|
||||
{
|
||||
u64 newTicks = CoreTiming::GetTicks();
|
||||
u64 newIdleTicks = CoreTiming::GetIdleTicks();
|
||||
|
||||
s64 diff = (newTicks - ticks)/1000000;
|
||||
s64 idleDiff = (newIdleTicks - idleTicks)/1000000;
|
||||
|
||||
ticks = newTicks;
|
||||
idleTicks = newIdleTicks;
|
||||
|
||||
float t = (float)(Timer.GetTimeDifference()) / 1000.f;
|
||||
char isoName[64];
|
||||
isoName[0] = 0x00;
|
||||
char temp[256];
|
||||
sprintf(temp, "%s - FPS: %8.2f - %s - %i MHz (%i real, %i idle skipped) out of %i MHz",
|
||||
isoName, (float)frames / t,
|
||||
g_CoreStartupParameter.bUseDynarec ? "JIT" : "Interpreter",
|
||||
(int)(diff),
|
||||
(int)(diff-idleDiff),
|
||||
(int)(idleDiff),
|
||||
SystemTimers::GetTicksPerSecond()/1000000);
|
||||
|
||||
if( g_pUpdateFPSDisplay != NULL )
|
||||
g_pUpdateFPSDisplay(temp);
|
||||
|
||||
frames = 0;
|
||||
Timer.Update();
|
||||
}
|
||||
PatchEngine_ApplyFramePatches();
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_DSPLog
|
||||
// WARNING - THIS MAY EXECUTED FROM DSP THREAD
|
||||
void Callback_DSPLog(const TCHAR* _szMessage)
|
||||
{
|
||||
LOG(AUDIO, _szMessage);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_DSPInterrupt
|
||||
// WARNING - THIS MAY EXECUTED FROM DSP THREAD
|
||||
void Callback_DSPInterrupt()
|
||||
{
|
||||
DSP::GenerateDSPInterruptFromPlugin(DSP::INT_DSP);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_DVDLog
|
||||
//
|
||||
void Callback_DVDLog(TCHAR* _szMessage)
|
||||
{
|
||||
LOG(DVDINTERFACE, _szMessage);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_DVDSetStatusbar
|
||||
//
|
||||
void Callback_DVDSetStatusbar(TCHAR* _szMessage)
|
||||
{
|
||||
//Todo: PostMessage to main window to set the string
|
||||
// strDVDMessage = _szMessage;
|
||||
// if (g_CoreStartupParameter.m_StatusUpdate != NULL)
|
||||
// g_CoreStartupParameter.m_StatusUpdate();
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Callback_PADLog
|
||||
//
|
||||
void Callback_PADLog(const TCHAR* _szMessage)
|
||||
{
|
||||
LOG(SERIALINTERFACE, _szMessage);
|
||||
}
|
||||
|
||||
} // end of namespace Core
|
65
Source/Core/Core/Src/Core.h
Normal file
65
Source/Core/Core/Src/Core.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _CORE_H
|
||||
#define _CORE_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include "CoreParameter.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
enum EState
|
||||
{
|
||||
CORE_UNINITIALIZED,
|
||||
CORE_PAUSE,
|
||||
CORE_RUN,
|
||||
};
|
||||
|
||||
// Init core
|
||||
bool Init(const SCoreStartupParameter _CoreParameter);
|
||||
void Stop();
|
||||
|
||||
// Get state
|
||||
bool SetState(EState _State);
|
||||
|
||||
// Get state
|
||||
EState GetState();
|
||||
|
||||
// get core parameters
|
||||
extern SCoreStartupParameter g_CoreStartupParameter; //uck
|
||||
const SCoreStartupParameter& GetStartupParameter();
|
||||
|
||||
// make a screen shot
|
||||
bool MakeScreenshot(const std::string& _rFilename);
|
||||
void* GetWindowHandle();
|
||||
|
||||
extern bool bReadTrace;
|
||||
extern bool bWriteTrace;
|
||||
|
||||
void StartTrace(bool write);
|
||||
|
||||
int SyncTrace();
|
||||
void SetBlockStart(u32 addr);
|
||||
void StopTrace();
|
||||
|
||||
} // end of namespace Core
|
||||
|
||||
#endif
|
||||
|
144
Source/Core/Core/Src/CoreParameter.cpp
Normal file
144
Source/Core/Core/Src/CoreParameter.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Boot/Boot.h"
|
||||
#include "StringUtil.h"
|
||||
#include "CoreParameter.h"
|
||||
#include "VolumeCreator.h"
|
||||
|
||||
SCoreStartupParameter::SCoreStartupParameter()
|
||||
{
|
||||
LoadDefaults();
|
||||
}
|
||||
|
||||
void SCoreStartupParameter::LoadDefaults()
|
||||
{
|
||||
bEnableDebugging = false;
|
||||
bUseDynarec = false;
|
||||
bUseDualCore = false;
|
||||
bRunCompareServer = false;
|
||||
bWii = false;
|
||||
}
|
||||
|
||||
|
||||
bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios)
|
||||
{
|
||||
static const char *s_DataBasePath_EUR = "Data_EUR";
|
||||
static const char *s_DataBasePath_USA = "Data_USA";
|
||||
static const char *s_DataBasePath_JAP = "Data_JAP";
|
||||
|
||||
std::string BaseDataPath(s_DataBasePath_EUR);
|
||||
|
||||
switch (_BootBios)
|
||||
{
|
||||
case BOOT_DEFAULT:
|
||||
{
|
||||
std::string Extension;
|
||||
SplitPath(m_strFilename, NULL, NULL, &Extension);
|
||||
|
||||
if (!stricmp(Extension.c_str(), ".gcm") ||
|
||||
!stricmp(Extension.c_str(), ".iso") ||
|
||||
!stricmp(Extension.c_str(), ".gcz") )
|
||||
{
|
||||
m_BootType = BOOT_ISO;
|
||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
|
||||
if (pVolume == NULL)
|
||||
{
|
||||
PanicAlert("Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bWii = DiscIO::IsVolumeWiiDisc(*pVolume);
|
||||
|
||||
switch (pVolume->GetCountry())
|
||||
{
|
||||
case DiscIO::IVolume::COUNTRY_USA:
|
||||
bNTSC = true;
|
||||
BaseDataPath = s_DataBasePath_USA;
|
||||
break;
|
||||
|
||||
case DiscIO::IVolume::COUNTRY_JAP:
|
||||
bNTSC = true;
|
||||
BaseDataPath = s_DataBasePath_JAP;
|
||||
break;
|
||||
|
||||
case DiscIO::IVolume::COUNTRY_EUROPE:
|
||||
case DiscIO::IVolume::COUNTRY_FRANCE:
|
||||
bNTSC = false;
|
||||
BaseDataPath = s_DataBasePath_EUR;
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlert("Your GCM/ISO file seems to be invalid (invalid country).");
|
||||
return false;
|
||||
}
|
||||
|
||||
delete pVolume;
|
||||
}
|
||||
else if (!stricmp(Extension.c_str(), ".elf"))
|
||||
{
|
||||
bWii = CBoot::IsElfWii(m_strFilename.c_str());
|
||||
BaseDataPath = s_DataBasePath_USA;
|
||||
m_BootType = BOOT_ELF;
|
||||
bNTSC = true;
|
||||
}
|
||||
else if (!stricmp(Extension.c_str(), ".bin"))
|
||||
{
|
||||
BaseDataPath = s_DataBasePath_USA;
|
||||
m_BootType = BOOT_BIN;
|
||||
bNTSC = true;
|
||||
}
|
||||
else if (!stricmp(Extension.c_str(), ".dol"))
|
||||
{
|
||||
BaseDataPath = s_DataBasePath_USA;
|
||||
m_BootType = BOOT_DOL;
|
||||
bNTSC = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Could not recognize ISO file %s", m_strFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BOOT_BIOS_USA:
|
||||
BaseDataPath = s_DataBasePath_USA;
|
||||
m_strFilename.clear();
|
||||
bNTSC = true;
|
||||
break;
|
||||
|
||||
case BOOT_BIOS_JAP:
|
||||
BaseDataPath = s_DataBasePath_JAP;
|
||||
m_strFilename.clear();
|
||||
bNTSC = true;
|
||||
break;
|
||||
|
||||
case BOOT_BIOS_EUR:
|
||||
BaseDataPath = s_DataBasePath_EUR;
|
||||
m_strFilename.clear();
|
||||
bNTSC = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// setup paths
|
||||
m_strBios = BaseDataPath + "/IPL.bin";
|
||||
m_strMemoryCardA = BaseDataPath + "/MemoryCardA.raw";
|
||||
m_strMemoryCardB = BaseDataPath + "/MemoryCardB.raw";
|
||||
m_strSRAM = BaseDataPath + "/SRAM.raw";
|
||||
}
|
89
Source/Core/Core/Src/CoreParameter.h
Normal file
89
Source/Core/Core/Src/CoreParameter.h
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _COREPARAMETER_H
|
||||
#define _COREPARAMETER_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
struct SCoreStartupParameter
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HINSTANCE hInstance;
|
||||
#endif
|
||||
|
||||
// windows/GUI related
|
||||
void* hMainWindow;
|
||||
|
||||
// flags
|
||||
bool bEnableDebugging;
|
||||
bool bUseDynarec;
|
||||
bool bUseDualCore;
|
||||
bool bNTSC;
|
||||
bool bHLEBios;
|
||||
bool bThrottle;
|
||||
bool bUseFastMem;
|
||||
|
||||
bool bRunCompareServer;
|
||||
bool bRunCompareClient;
|
||||
|
||||
bool bWii;
|
||||
|
||||
enum EBootBios
|
||||
{
|
||||
BOOT_DEFAULT,
|
||||
BOOT_BIOS_JAP,
|
||||
BOOT_BIOS_USA,
|
||||
BOOT_BIOS_EUR,
|
||||
};
|
||||
|
||||
enum EBootType
|
||||
{
|
||||
BOOT_ISO,
|
||||
BOOT_ELF,
|
||||
BOOT_BIN,
|
||||
BOOT_DOL,
|
||||
BOOT_BIOS
|
||||
};
|
||||
EBootType m_BootType;
|
||||
|
||||
|
||||
// files
|
||||
std::string m_strVideoPlugin;
|
||||
std::string m_strPadPlugin;
|
||||
std::string m_strDSPPlugin;
|
||||
|
||||
std::string m_strFilename;
|
||||
std::string m_strBios;
|
||||
std::string m_strMemoryCardA;
|
||||
std::string m_strMemoryCardB;
|
||||
std::string m_strSRAM;
|
||||
std::string m_strDefaultGCM;
|
||||
|
||||
//
|
||||
SCoreStartupParameter();
|
||||
|
||||
void LoadDefaults();
|
||||
bool AutoSetup(EBootBios _BootBios);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
270
Source/Core/Core/Src/CoreTiming.cpp
Normal file
270
Source/Core/Core/Src/CoreTiming.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Thread.h"
|
||||
#include "PowerPC/PowerPC.h"
|
||||
#include "CoreTiming.h"
|
||||
|
||||
// TODO(ector): Replace new/delete in this file with a simple memory pool
|
||||
// Don't expect a massive speedup though.
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
int downcount, slicelength;
|
||||
int maxSliceLength = 20000;
|
||||
|
||||
s64 globalTimer;
|
||||
s64 idledCycles;
|
||||
|
||||
u64 GetTicks()
|
||||
{
|
||||
return (u64)globalTimer;
|
||||
}
|
||||
|
||||
u64 GetIdleTicks()
|
||||
{
|
||||
return (u64)idledCycles;
|
||||
}
|
||||
|
||||
struct Event
|
||||
{
|
||||
TimedCallback callback;
|
||||
Event *next;
|
||||
s64 time;
|
||||
u64 userdata;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
Event *first;
|
||||
Event *tsFirst;
|
||||
|
||||
Common::CriticalSection externalEventSection;
|
||||
|
||||
// This is to be called when outside threads, such as the graphics thread, wants to
|
||||
// schedule things to be executed on the main thread.
|
||||
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata)
|
||||
{
|
||||
externalEventSection.Enter();
|
||||
Event *ne = new Event;
|
||||
ne->time = globalTimer + cyclesIntoFuture;
|
||||
ne->name = name;
|
||||
ne->callback = callback;
|
||||
ne->next = tsFirst;
|
||||
ne->userdata = userdata;
|
||||
tsFirst = ne;
|
||||
externalEventSection.Leave();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
globalTimer = 0;
|
||||
idledCycles = 0;
|
||||
while (first)
|
||||
{
|
||||
Event *e = first->next;
|
||||
delete [] first;
|
||||
first = e;
|
||||
}
|
||||
}
|
||||
|
||||
void AddEventToQueue(Event *ne)
|
||||
{
|
||||
// Damn, this logic got complicated. Must be an easier way.
|
||||
if (!first)
|
||||
{
|
||||
first = ne;
|
||||
ne->next = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Event *ptr = first;
|
||||
Event *prev = 0;
|
||||
if (ptr->time > ne->time)
|
||||
{
|
||||
ne->next = first;
|
||||
first = ne;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = first;
|
||||
ptr = first->next;
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr->time <= ne->time)
|
||||
{
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
//OK, ptr points to the item AFTER our new item. Let's insert
|
||||
ne->next = prev->next;
|
||||
prev->next = ne;
|
||||
// Done!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This must be run ONLY from within the cpu thread
|
||||
// cyclesIntoFuture may be VERY inaccurate if called from anything else
|
||||
// than Advance
|
||||
void ScheduleEvent(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata)
|
||||
{
|
||||
Event *ne = new Event;
|
||||
ne->callback = callback;
|
||||
ne->userdata = userdata;
|
||||
ne->name = name;
|
||||
ne->time = globalTimer + cyclesIntoFuture;
|
||||
|
||||
AddEventToQueue(ne);
|
||||
}
|
||||
|
||||
void (*advanceCallback)(int cyclesExecuted);
|
||||
|
||||
|
||||
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
|
||||
{
|
||||
advanceCallback = callback;
|
||||
}
|
||||
|
||||
bool IsScheduled(TimedCallback callback)
|
||||
{
|
||||
if (!first)
|
||||
return false;
|
||||
Event *e = first;
|
||||
while (e) {
|
||||
if (e->callback == callback)
|
||||
return true;
|
||||
e = e->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RemoveEvent(TimedCallback callback)
|
||||
{
|
||||
if (!first)
|
||||
return;
|
||||
if (first->callback == callback)
|
||||
{
|
||||
Event *next = first->next;
|
||||
delete first;
|
||||
first = next;
|
||||
}
|
||||
if (!first)
|
||||
return;
|
||||
Event *prev = first;
|
||||
Event *ptr = prev->next;
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr->callback == callback)
|
||||
{
|
||||
prev->next = ptr->next;
|
||||
delete ptr;
|
||||
ptr = prev->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetMaximumSlice(int maximumSliceLength)
|
||||
{
|
||||
maxSliceLength = maximumSliceLength;
|
||||
}
|
||||
|
||||
|
||||
void Advance()
|
||||
{
|
||||
// Move events from async queue into main queue
|
||||
externalEventSection.Enter();
|
||||
while (tsFirst)
|
||||
{
|
||||
//MessageBox(0,"yay",0,0);
|
||||
Event *next = tsFirst->next;
|
||||
AddEventToQueue(tsFirst);
|
||||
tsFirst = next;
|
||||
}
|
||||
externalEventSection.Leave();
|
||||
|
||||
// we are out of run, downcount = -3
|
||||
int cyclesExecuted = slicelength - downcount;
|
||||
// sliceLength = downac
|
||||
|
||||
globalTimer += cyclesExecuted;
|
||||
|
||||
while (first)
|
||||
{
|
||||
if (first->time <= globalTimer)
|
||||
{
|
||||
// LOG(GEKKO, "[Scheduler] %s (%lld, %lld) ",
|
||||
// first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
|
||||
|
||||
first->callback(first->userdata, (int)(globalTimer - first->time));
|
||||
|
||||
Event *next = first->next;
|
||||
delete first;
|
||||
first = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!first)
|
||||
{
|
||||
LOG(GEKKO, "WARNING - no events in queue. Setting downcount to 10000");
|
||||
downcount += 10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
slicelength = (int)(first->time - globalTimer);
|
||||
if (slicelength > maxSliceLength)
|
||||
slicelength = maxSliceLength;
|
||||
downcount = slicelength;
|
||||
}
|
||||
if (advanceCallback)
|
||||
advanceCallback(cyclesExecuted);
|
||||
}
|
||||
|
||||
void LogPendingEvents()
|
||||
{
|
||||
Event *ptr = first;
|
||||
while (ptr)
|
||||
{
|
||||
LOG(GEKKO, "PENDING: Now: %lld Pending: %lld %s", globalTimer, ptr->time, ptr->name);
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
|
||||
void Idle()
|
||||
{
|
||||
LOG(GEKKO, "Idle");
|
||||
|
||||
idledCycles += downcount;
|
||||
downcount = 0;
|
||||
|
||||
Advance();
|
||||
}
|
||||
|
||||
|
||||
}; // end of namespace
|
54
Source/Core/Core/Src/CoreTiming.h
Normal file
54
Source/Core/Core/Src/CoreTiming.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _CORETIMING_H
|
||||
#define _CORETIMING_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
|
||||
enum {
|
||||
SOON = 100
|
||||
};
|
||||
|
||||
typedef void (*TimedCallback)(u64 userdata, int cyclesLate);
|
||||
|
||||
u64 GetTicks();
|
||||
u64 GetIdleTicks();
|
||||
// The int that the callbacks get is how many cycles late it was.
|
||||
// So to schedule a new event on a regular basis:
|
||||
// inside callback:
|
||||
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
|
||||
void ScheduleEvent(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata=0);
|
||||
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, TimedCallback callback, const char *name, u64 userdata=0);
|
||||
void RemoveEvent(TimedCallback callback);
|
||||
bool IsScheduled(TimedCallback callback);
|
||||
void Advance();
|
||||
void Idle();
|
||||
void Clear();
|
||||
void LogPendingEvents();
|
||||
void SetMaximumSlice(int maximumSliceLength);
|
||||
|
||||
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted));
|
||||
|
||||
extern int downcount;
|
||||
extern int slicelength;
|
||||
|
||||
}; // end of namespace
|
||||
|
||||
#endif
|
27
Source/Core/Core/Src/Debugger/DebugInterface.h
Normal file
27
Source/Core/Core/Src/Debugger/DebugInterface.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _DEBUGINTERFACE_H
|
||||
#define _DEBUGINTERFACE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class DebugInterface
|
||||
{
|
||||
public:
|
||||
virtual const char *disasm(unsigned int /*address*/) {return "NODEBUGGER";}
|
||||
virtual int getInstructionSize(int /*instruction*/) {return 1;}
|
||||
|
||||
virtual bool isAlive() {return true;}
|
||||
virtual bool isBreakpoint(unsigned int /*address*/) {return false;}
|
||||
virtual void setBreakpoint(unsigned int /*address*/){}
|
||||
virtual void clearBreakpoint(unsigned int /*address*/){}
|
||||
virtual void clearAllBreakpoints() {}
|
||||
virtual void toggleBreakpoint(unsigned int /*address*/){}
|
||||
virtual unsigned int readMemory(unsigned int /*address*/){return 0;}
|
||||
virtual unsigned int getPC() {return 0;}
|
||||
virtual void setPC(unsigned int /*address*/) {}
|
||||
virtual void step() {}
|
||||
virtual void runToBreakpoint() {}
|
||||
virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;}
|
||||
virtual std::string getDescription(unsigned int /*address*/) = 0;
|
||||
};
|
||||
|
||||
#endif
|
147
Source/Core/Core/Src/Debugger/Debugger_BreakPoints.cpp
Normal file
147
Source/Core/Core/Src/Debugger/Debugger_BreakPoints.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
// Lame slow breakpoint system
|
||||
// TODO: a real one
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "../HW/CPU.h"
|
||||
|
||||
#include "Debugger_SymbolMap.h"
|
||||
#include "Debugger_BreakPoints.h"
|
||||
|
||||
using namespace Debugger;
|
||||
|
||||
std::vector<TBreakPoint> CBreakPoints::m_iBreakPoints;
|
||||
std::vector<TMemCheck> CBreakPoints::MemChecks;
|
||||
u32 CBreakPoints::m_iBreakOnCount = 0;
|
||||
|
||||
TMemCheck::TMemCheck()
|
||||
{
|
||||
numHits = 0;
|
||||
}
|
||||
|
||||
void TMemCheck::Action(u32 iValue, u32 addr, bool write, int size, u32 pc)
|
||||
{
|
||||
if ((write && bOnWrite) || (!write && bOnRead))
|
||||
{
|
||||
if (bLog)
|
||||
{
|
||||
const char *copy = Debugger::GetDescription(addr);
|
||||
LOG(MEMMAP,"CHK %08x %s%i at %08x (%s)", iValue, write ? "Write" : "Read", size*8, addr, copy);
|
||||
}
|
||||
if (bBreak)
|
||||
CCPU::Break();
|
||||
}
|
||||
}
|
||||
|
||||
bool CBreakPoints::IsAddressBreakPoint(u32 _iAddress)
|
||||
{
|
||||
std::vector<TBreakPoint>::iterator iter;
|
||||
|
||||
for (iter = m_iBreakPoints.begin(); iter != m_iBreakPoints.end(); ++iter)
|
||||
if ((*iter).iAddress == _iAddress)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBreakPoints::IsTempBreakPoint(u32 _iAddress)
|
||||
{
|
||||
std::vector<TBreakPoint>::iterator iter;
|
||||
|
||||
for (iter = m_iBreakPoints.begin(); iter != m_iBreakPoints.end(); ++iter)
|
||||
if ((*iter).iAddress == _iAddress && (*iter).bTemporary)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TMemCheck *CBreakPoints::GetMemCheck(u32 address)
|
||||
{
|
||||
std::vector<TMemCheck>::iterator iter;
|
||||
for (iter = MemChecks.begin(); iter != MemChecks.end(); ++iter)
|
||||
{
|
||||
if ((*iter).bRange)
|
||||
{
|
||||
if (address >= (*iter).iStartAddress && address <= (*iter).iEndAddress)
|
||||
return &(*iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*iter).iStartAddress==address)
|
||||
return &(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
//none found
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
|
||||
{
|
||||
if (!IsAddressBreakPoint(_iAddress))
|
||||
{
|
||||
TBreakPoint pt;
|
||||
pt.bOn = true;
|
||||
pt.bTemporary = temp;
|
||||
pt.iAddress = _iAddress;
|
||||
|
||||
m_iBreakPoints.push_back(pt);
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
|
||||
{
|
||||
std::vector<TBreakPoint>::iterator iter;
|
||||
|
||||
for (iter = m_iBreakPoints.begin(); iter != m_iBreakPoints.end(); ++iter)
|
||||
{
|
||||
if ((*iter).iAddress == _iAddress)
|
||||
{
|
||||
m_iBreakPoints.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPoints::ClearAllBreakPoints()
|
||||
{
|
||||
m_iBreakPoints.clear();
|
||||
}
|
||||
|
||||
void CBreakPoints::AddAutoBreakpoints()
|
||||
{
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#if 1
|
||||
const char *bps[] = {
|
||||
"PPCHalt",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(bps) / sizeof(const char *); i++)
|
||||
{
|
||||
XSymbolIndex idx = FindSymbol(bps[i]);
|
||||
if (idx != 0)
|
||||
{
|
||||
const CSymbol &symbol = GetSymbol(idx);
|
||||
AddBreakPoint(symbol.vaddress, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
89
Source/Core/Core/Src/Debugger/Debugger_BreakPoints.h
Normal file
89
Source/Core/Core/Src/Debugger/Debugger_BreakPoints.h
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _DEBUGGER_BREAKPOINTS_H
|
||||
#define _DEBUGGER_BREAKPOINTS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
struct TBreakPoint
|
||||
{
|
||||
u32 iAddress;
|
||||
bool bOn;
|
||||
bool bTemporary;
|
||||
};
|
||||
|
||||
struct TMemCheck
|
||||
{
|
||||
TMemCheck();
|
||||
u32 iStartAddress;
|
||||
u32 iEndAddress;
|
||||
|
||||
bool bRange;
|
||||
|
||||
bool bOnRead;
|
||||
bool bOnWrite;
|
||||
|
||||
bool bLog;
|
||||
bool bBreak;
|
||||
|
||||
u32 numHits;
|
||||
|
||||
void Action(u32 _iValue, u32 addr, bool write, int size, u32 pc);
|
||||
};
|
||||
|
||||
class CBreakPoints
|
||||
{
|
||||
private:
|
||||
|
||||
enum { MAX_NUMBER_OF_CALLSTACK_ENTRIES = 16384};
|
||||
enum { MAX_NUMBER_OF_BREAKPOINTS = 16};
|
||||
|
||||
static std::vector<TBreakPoint> m_iBreakPoints;
|
||||
|
||||
static u32 m_iBreakOnCount;
|
||||
|
||||
public:
|
||||
static std::vector<TMemCheck> MemChecks;
|
||||
|
||||
// is address breakpoint
|
||||
static bool IsAddressBreakPoint(u32 _iAddress);
|
||||
|
||||
//memory breakpoint
|
||||
static TMemCheck *GetMemCheck(u32 address);
|
||||
|
||||
// is break on count
|
||||
static void SetBreakCount(u32 count) { m_iBreakOnCount = count; }
|
||||
static u32 GetBreakCount() { return m_iBreakOnCount; }
|
||||
|
||||
static bool IsTempBreakPoint(u32 _iAddress);
|
||||
|
||||
// AddBreakPoint
|
||||
static void AddBreakPoint(u32 _iAddress, bool temp=false);
|
||||
|
||||
// Remove Breakpoint
|
||||
static void RemoveBreakPoint(u32 _iAddress);
|
||||
|
||||
static void ClearAllBreakPoints();
|
||||
|
||||
static void AddAutoBreakpoints();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
433
Source/Core/Core/Src/Debugger/Debugger_SymbolMap.cpp
Normal file
433
Source/Core/Core/Src/Debugger/Debugger_SymbolMap.cpp
Normal file
@ -0,0 +1,433 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include "Common.h"
|
||||
#include "StringUtil.h"
|
||||
#include "Debugger_SymbolMap.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../PowerPC/PPCAnalyst.h"
|
||||
#include "../../../../Externals/Bochs_disasm/PowerPCDisasm.h"
|
||||
|
||||
namespace Debugger
|
||||
{
|
||||
|
||||
XVectorSymbol m_VectorSymbols;
|
||||
|
||||
CSymbol::CSymbol(u32 _Address, u32 _Size, ESymbolType _Type, const char *_rName) :
|
||||
vaddress(_Address),
|
||||
size(_Size),
|
||||
runCount(0),
|
||||
type(_Type),
|
||||
m_strName(_rName)
|
||||
{
|
||||
// invalid entry
|
||||
if (m_strName.size() < 2)
|
||||
{
|
||||
_Address = -1;
|
||||
_Size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CSymbol::~CSymbol()
|
||||
{
|
||||
m_vecBackwardLinks.clear();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_VectorSymbols.clear();
|
||||
|
||||
// 0 is an invalid entry
|
||||
CSymbol Invalid(-1, 0, ST_FUNCTION, "Invalid");
|
||||
m_VectorSymbols.push_back(Invalid);
|
||||
}
|
||||
|
||||
XSymbolIndex AddSymbol(const CSymbol& _rSymbolMapEntry)
|
||||
{
|
||||
XSymbolIndex old = 0;
|
||||
if ((old = FindSymbol(_rSymbolMapEntry.GetName().c_str())) != 0)
|
||||
return old;
|
||||
m_VectorSymbols.push_back(_rSymbolMapEntry);
|
||||
return (XSymbolIndex)(m_VectorSymbols.size()-1);
|
||||
}
|
||||
|
||||
const CSymbol& GetSymbol(XSymbolIndex _Index)
|
||||
{
|
||||
if (_Index < (XSymbolIndex)m_VectorSymbols.size())
|
||||
return m_VectorSymbols[_Index];
|
||||
|
||||
PanicAlert("GetSymbol is called with an invalid index %i", _Index);
|
||||
return m_VectorSymbols[0];
|
||||
}
|
||||
|
||||
const XVectorSymbol& AccessSymbols()
|
||||
{
|
||||
return m_VectorSymbols;
|
||||
}
|
||||
|
||||
CSymbol& AccessSymbol(XSymbolIndex _Index)
|
||||
{
|
||||
if (_Index < (XSymbolIndex)m_VectorSymbols.size())
|
||||
return m_VectorSymbols[_Index];
|
||||
|
||||
PanicAlert("AccessSymbol is called with an invalid index %i", _Index);
|
||||
return m_VectorSymbols[0];
|
||||
}
|
||||
|
||||
XSymbolIndex FindSymbol(u32 _Address)
|
||||
{
|
||||
for (int i = 0; i < (int)m_VectorSymbols.size(); i++)
|
||||
{
|
||||
const CSymbol& rSymbol = m_VectorSymbols[i];
|
||||
if ((_Address >= rSymbol.vaddress) && (_Address < rSymbol.vaddress + rSymbol.size))
|
||||
{
|
||||
return (XSymbolIndex)i;
|
||||
}
|
||||
}
|
||||
|
||||
// invalid index
|
||||
return 0;
|
||||
}
|
||||
|
||||
XSymbolIndex FindSymbol(const char *name)
|
||||
{
|
||||
for (int i = 0; i < (int)m_VectorSymbols.size(); i++)
|
||||
{
|
||||
const CSymbol& rSymbol = m_VectorSymbols[i];
|
||||
if (stricmp(rSymbol.GetName().c_str(), name) == 0)
|
||||
{
|
||||
return (XSymbolIndex)i;
|
||||
}
|
||||
}
|
||||
|
||||
// invalid index
|
||||
return 0;
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// LoadSymbolMap
|
||||
//
|
||||
bool LoadSymbolMap(const char *_szFilename)
|
||||
{
|
||||
Reset();
|
||||
|
||||
FILE *f = fopen(_szFilename, "r");
|
||||
if (!f)
|
||||
return false;
|
||||
//char temp[256];
|
||||
//fgets(temp,255,f); //.text section layout
|
||||
//fgets(temp,255,f); // Starting Virtual
|
||||
//fgets(temp,255,f); // address Size address
|
||||
//fgets(temp,255,f); // -----------------------
|
||||
|
||||
bool started=false;
|
||||
|
||||
while (!feof(f))
|
||||
{
|
||||
char line[512],temp[256];
|
||||
fgets(line,511,f);
|
||||
if (strlen(line)<4)
|
||||
continue;
|
||||
|
||||
sscanf(line,"%s",temp);
|
||||
if (strcmp(temp,"UNUSED")==0) continue;
|
||||
if (strcmp(temp,".text")==0) {started = true; continue;};
|
||||
if (strcmp(temp,".init")==0) {started = true; continue;};
|
||||
if (strcmp(temp,"Starting")==0) continue;
|
||||
if (strcmp(temp,"extab")==0) continue;
|
||||
if (strcmp(temp,".ctors")==0) break; //uh?
|
||||
if (strcmp(temp,".dtors")==0) break;
|
||||
if (strcmp(temp,".rodata")==0) continue;
|
||||
if (strcmp(temp,".data")==0) continue;
|
||||
if (strcmp(temp,".sbss")==0) continue;
|
||||
if (strcmp(temp,".sdata")==0) continue;
|
||||
if (strcmp(temp,".sdata2")==0) continue;
|
||||
if (strcmp(temp,"address")==0) continue;
|
||||
if (strcmp(temp,"-----------------------")==0) continue;
|
||||
if (strcmp(temp,".sbss2")==0) break;
|
||||
if (temp[1]==']') continue;
|
||||
|
||||
if (!started) continue;
|
||||
|
||||
// read out the entry
|
||||
u32 address, vaddress, size, unknown;
|
||||
char name[512];
|
||||
sscanf(line,"%08x %08x %08x %i %s",&address, &size, &vaddress, &unknown, name);
|
||||
|
||||
char *namepos = strstr(line, name);
|
||||
if (namepos != 0) //would be odd if not :P
|
||||
strcpy(name, namepos);
|
||||
name[strlen(name)-1] = 0;
|
||||
|
||||
// we want the function names only ....
|
||||
for (size_t i=0; i<strlen(name); i++)
|
||||
{
|
||||
if (name[i] == ' ') name[i] = 0x00;
|
||||
if (name[i] == '(') name[i] = 0x00;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// check if this is a valid entry
|
||||
if (strcmp(name,".text")!=0 ||
|
||||
strcmp(name,".init")!=0 ||
|
||||
strlen(name) > 0)
|
||||
{
|
||||
AddSymbol(CSymbol(vaddress | 0x80000000, size, ST_FUNCTION, name));
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
// AnalyzeBackwards();
|
||||
return true;
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// SaveSymbolMap
|
||||
//
|
||||
void SaveSymbolMap(const char *_rFilename)
|
||||
{
|
||||
FILE *f = fopen(_rFilename,"w");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
fprintf(f,".text\n");
|
||||
XVectorSymbol::const_iterator itr = m_VectorSymbols.begin();
|
||||
while(itr != m_VectorSymbols.end())
|
||||
{
|
||||
const CSymbol& rSymbol = *itr;
|
||||
fprintf(f,"%08x %08x %08x %i %s\n",rSymbol.vaddress,rSymbol.size,rSymbol.vaddress,0,rSymbol.GetName().c_str());
|
||||
itr++;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================================================
|
||||
|
||||
|
||||
void MergeMapWithDB(const char *beginning)
|
||||
{
|
||||
XVectorSymbol::const_iterator itr = m_VectorSymbols.begin();
|
||||
while(itr != m_VectorSymbols.end())
|
||||
{
|
||||
const CSymbol& rSymbol = *itr;
|
||||
|
||||
if (rSymbol.type == ST_FUNCTION && rSymbol.size>=12)
|
||||
{
|
||||
// if (!beginning || !strlen(beginning) || !(memcmp(beginning,rSymbol.name,strlen(beginning))))
|
||||
PPCAnalyst::AddToFuncDB(rSymbol.vaddress, rSymbol.size, rSymbol.GetName().c_str());
|
||||
}
|
||||
|
||||
itr++;
|
||||
}
|
||||
|
||||
PPCAnalyst::UseFuncDB();
|
||||
|
||||
PPCAnalyst::SaveFuncDB("e:\\test.db");
|
||||
|
||||
// PanicAlert("MergeMapWiintthDB : %s", beginning);
|
||||
}
|
||||
|
||||
void GetFromAnalyzer()
|
||||
{
|
||||
struct local {static void AddSymb(PPCAnalyst::SFunction *f)
|
||||
{
|
||||
Debugger::AddSymbol(CSymbol(f->address, f->size*4, ST_FUNCTION, f->name.c_str()));
|
||||
}};
|
||||
PPCAnalyst::GetAllFuncs(local::AddSymb);
|
||||
}
|
||||
|
||||
const char *GetDescription(u32 _Address)
|
||||
{
|
||||
Debugger::XSymbolIndex Index = Debugger::FindSymbol(_Address);
|
||||
if (Index > 0)
|
||||
return GetSymbol(Index).GetName().c_str();
|
||||
else
|
||||
return "(unk.)";
|
||||
}
|
||||
|
||||
//
|
||||
// --- shouldn't be here ---
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
||||
void FillSymbolListBox(HWND listbox, ESymbolType symmask)
|
||||
{
|
||||
ShowWindow(listbox,SW_HIDE);
|
||||
ListBox_ResetContent(listbox);
|
||||
|
||||
int style = GetWindowLong(listbox,GWL_STYLE);
|
||||
|
||||
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x80000000)"),0x80000000);
|
||||
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x81FFFFFF)"),0x81FFFFFF);
|
||||
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x80003100)"),0x80003100);
|
||||
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x90000000)"),0x90000000);
|
||||
ListBox_SetItemData(listbox,ListBox_AddString(listbox,"_(0x93FFFFFF)"),0x93FFFFFF);
|
||||
|
||||
XVectorSymbol::const_iterator itr = m_VectorSymbols.begin();
|
||||
while (itr != m_VectorSymbols.end())
|
||||
{
|
||||
const CSymbol& rSymbol = *itr;
|
||||
if (rSymbol.type & symmask)
|
||||
{
|
||||
int index = ListBox_AddString(listbox,rSymbol.GetName().c_str());
|
||||
ListBox_SetItemData(listbox,index,rSymbol.vaddress);
|
||||
}
|
||||
itr++;
|
||||
}
|
||||
|
||||
ShowWindow(listbox,SW_SHOW);
|
||||
}
|
||||
|
||||
void FillListBoxBLinks(HWND listbox, XSymbolIndex _Index)
|
||||
{
|
||||
/* ListBox_ResetContent(listbox);
|
||||
|
||||
int style = GetWindowLong(listbox,GWL_STYLE);
|
||||
|
||||
CSymbol &e = entries[num];*/
|
||||
#ifdef BWLINKS
|
||||
for (int i=0; i<e.backwardLinks.size(); i++)
|
||||
{
|
||||
u32 addr = e.backwardLinks[i];
|
||||
int index = ListBox_AddString(listbox,GetSymbolName(GetSymbolNum(addr)));
|
||||
ListBox_SetItemData(listbox,index,addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void AnalyzeBackwards()
|
||||
{
|
||||
#ifndef BWLINKS
|
||||
return;
|
||||
#else
|
||||
for (int i=0; i<numEntries; i++)
|
||||
{
|
||||
u32 ptr = entries[i].vaddress;
|
||||
if (ptr && entries[i].type == ST_FUNCTION)
|
||||
{
|
||||
for (int a = 0; a<entries[i].size/4; a++)
|
||||
{
|
||||
u32 inst = Memory::ReadUnchecked_U32(ptr);
|
||||
switch (inst>>26)
|
||||
{
|
||||
case 18:
|
||||
if (LK) //LK
|
||||
{
|
||||
u32 addr;
|
||||
if(AA)
|
||||
addr = SignExt26(LI << 2);
|
||||
else
|
||||
addr = ptr + SignExt26(LI << 2);
|
||||
|
||||
int funNum = GetSymbolNum(addr);
|
||||
if (funNum>=0)
|
||||
entries[funNum].backwardLinks.push_back(ptr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
ptr+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GetCallstack(std::vector<SCallstackEntry> &output)
|
||||
{
|
||||
if (!Memory::IsRAMAddress(PowerPC::ppcState.gpr[1]))
|
||||
return false;
|
||||
|
||||
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||
if (LR == 0) {
|
||||
SCallstackEntry entry;
|
||||
entry.Name = "(error: LR=0)";
|
||||
entry.vAddress = 0x0;
|
||||
output.push_back(entry);
|
||||
return false;
|
||||
}
|
||||
int count = 1;
|
||||
if (GetDescription(PowerPC::ppcState.pc) != GetDescription(LR))
|
||||
{
|
||||
SCallstackEntry entry;
|
||||
entry.Name = StringFromFormat(" * %s [ LR = %08x ]\n", Debugger::GetDescription(LR), LR);
|
||||
entry.vAddress = 0x0;
|
||||
count++;
|
||||
}
|
||||
|
||||
//walk the stack chain
|
||||
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
||||
{
|
||||
if (!Memory::IsRAMAddress(addr + 4))
|
||||
return false;
|
||||
|
||||
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
||||
const char *str = Debugger::GetDescription(func);
|
||||
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
||||
str = "(unknown)";
|
||||
|
||||
SCallstackEntry entry;
|
||||
entry.Name = StringFromFormat(" * %s [ addr = %08x ]\n", str, func);
|
||||
entry.vAddress = func;
|
||||
output.push_back(entry);
|
||||
|
||||
if (!Memory::IsRAMAddress(addr))
|
||||
return false;
|
||||
|
||||
addr = Memory::ReadUnchecked_U32(addr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintCallstack() {
|
||||
u32 addr = Memory::ReadUnchecked_U32(PowerPC::ppcState.gpr[1]); // SP
|
||||
|
||||
printf("\n == STACK TRACE - SP = %08x ==\n", PowerPC::ppcState.gpr[1]);
|
||||
|
||||
if (LR == 0) {
|
||||
printf(" LR = 0 - this is bad\n");
|
||||
}
|
||||
int count = 1;
|
||||
if (GetDescription(PowerPC::ppcState.pc) != GetDescription(LR))
|
||||
{
|
||||
printf(" * %s [ LR = %08x ]\n", Debugger::GetDescription(LR), LR);
|
||||
count++;
|
||||
}
|
||||
|
||||
//walk the stack chain
|
||||
while ((addr != 0xFFFFFFFF) && (addr != 0) && (count++ < 20) && (PowerPC::ppcState.gpr[1] != 0))
|
||||
{
|
||||
u32 func = Memory::ReadUnchecked_U32(addr + 4);
|
||||
const char *str = Debugger::GetDescription(func);
|
||||
if (!str || strlen(str) == 0 || !strcmp(str, "Invalid"))
|
||||
str = "(unknown)";
|
||||
printf( " * %s [ addr = %08x ]\n", str, func);
|
||||
addr = Memory::ReadUnchecked_U32(addr);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Debugger
|
||||
|
102
Source/Core/Core/Src/Debugger/Debugger_SymbolMap.h
Normal file
102
Source/Core/Core/Src/Debugger/Debugger_SymbolMap.h
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _DEBUGGER_SYMBOLMAP_H
|
||||
#define _DEBUGGER_SYMBOLMAP_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace Debugger
|
||||
{
|
||||
|
||||
enum ESymbolType
|
||||
{
|
||||
ST_FUNCTION = 1,
|
||||
ST_DATA = 2
|
||||
};
|
||||
|
||||
class CSymbol
|
||||
{
|
||||
public:
|
||||
u32 vaddress;
|
||||
u32 size;
|
||||
u32 runCount;
|
||||
|
||||
ESymbolType type;
|
||||
|
||||
CSymbol(u32 _Address, u32 _Size, ESymbolType _Type, const char *_rName);
|
||||
~CSymbol();
|
||||
|
||||
const std::string &GetName() const { return m_strName; }
|
||||
void SetName(const char *_rName) { m_strName = _rName; }
|
||||
|
||||
private:
|
||||
std::string m_strName;
|
||||
std::vector <u32> m_vecBackwardLinks;
|
||||
};
|
||||
|
||||
typedef int XSymbolIndex;
|
||||
typedef std::vector<CSymbol> XVectorSymbol;
|
||||
|
||||
void Reset();
|
||||
|
||||
XSymbolIndex AddSymbol(const CSymbol& _rSymbolMapEntry);
|
||||
|
||||
const CSymbol& GetSymbol(XSymbolIndex _Index);
|
||||
CSymbol& AccessSymbol(XSymbolIndex _Index);
|
||||
|
||||
const XVectorSymbol& AccessSymbols();
|
||||
|
||||
XSymbolIndex FindSymbol(u32 _Address);
|
||||
XSymbolIndex FindSymbol(const char *name);
|
||||
|
||||
bool LoadSymbolMap(const char *_rFilename);
|
||||
void SaveSymbolMap(const char *_rFilename);
|
||||
void PrintCallstack();
|
||||
|
||||
const char *GetDescription(u32 _Address);
|
||||
|
||||
bool RenameSymbol(XSymbolIndex _Index, const char *_Name);
|
||||
void AnalyzeBackwards();
|
||||
void GetFromAnalyzer();
|
||||
void MergeMapWithDB(const char *beginning);
|
||||
|
||||
struct SCallstackEntry
|
||||
{
|
||||
std::string Name;
|
||||
u32 vAddress;
|
||||
};
|
||||
|
||||
bool GetCallstack(std::vector<SCallstackEntry> &output);
|
||||
// TODO: move outta here
|
||||
#ifdef _WIN32
|
||||
}
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
namespace Debugger
|
||||
{
|
||||
void FillSymbolListBox(HWND listbox, ESymbolType symmask);
|
||||
void FillListBoxBLinks(HWND listbox, XSymbolIndex Index);
|
||||
#endif
|
||||
|
||||
} // end of namespace Debugger
|
||||
|
||||
#endif
|
||||
|
87
Source/Core/Core/Src/Debugger/Dump.cpp
Normal file
87
Source/Core/Core/Src/Debugger/Dump.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "Dump.h"
|
||||
|
||||
CDump::CDump(const char* _szFilename) :
|
||||
m_pData(NULL),
|
||||
m_bInit(false)
|
||||
{
|
||||
FILE* pStream = fopen(_szFilename, "rb");
|
||||
if (pStream != NULL)
|
||||
{
|
||||
fseek(pStream, 0, SEEK_END);
|
||||
m_size = ftell(pStream);
|
||||
fseek(pStream, 0, SEEK_SET);
|
||||
|
||||
m_pData = new u8[m_size];
|
||||
|
||||
fread(m_pData, m_size, 1, pStream);
|
||||
|
||||
fclose(pStream);
|
||||
}
|
||||
}
|
||||
|
||||
CDump::~CDump(void)
|
||||
{
|
||||
if (m_pData != NULL)
|
||||
{
|
||||
delete [] m_pData;
|
||||
m_pData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CDump::GetNumberOfSteps(void)
|
||||
{
|
||||
return (int)(m_size / STRUCTUR_SIZE);
|
||||
}
|
||||
|
||||
u32
|
||||
CDump::GetGPR(int _step, int _gpr)
|
||||
{
|
||||
u32 offset = _step * STRUCTUR_SIZE;
|
||||
|
||||
if (offset >= m_size)
|
||||
return -1;
|
||||
|
||||
return Read32(offset + OFFSET_GPR + (_gpr * 4));
|
||||
}
|
||||
|
||||
u32
|
||||
CDump::GetPC(int _step)
|
||||
{
|
||||
u32 offset = _step * STRUCTUR_SIZE;
|
||||
|
||||
if (offset >= m_size)
|
||||
return -1;
|
||||
|
||||
return Read32(offset + OFFSET_PC);
|
||||
}
|
||||
|
||||
u32
|
||||
CDump::Read32(u32 _pos)
|
||||
{
|
||||
u32 result = (m_pData[_pos+0] << 24) |
|
||||
(m_pData[_pos+1] << 16) |
|
||||
(m_pData[_pos+2] << 8) |
|
||||
(m_pData[_pos+3] << 0);
|
||||
|
||||
return result;
|
||||
}
|
52
Source/Core/Core/Src/Debugger/Dump.h
Normal file
52
Source/Core/Core/Src/Debugger/Dump.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// uncompress the dumps from costis GC-Debugger tool
|
||||
//
|
||||
//
|
||||
#ifndef _DUMP_H
|
||||
#define _DUMP_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class CDump
|
||||
{
|
||||
public:
|
||||
|
||||
CDump(const char* _szFilename);
|
||||
~CDump();
|
||||
|
||||
int GetNumberOfSteps();
|
||||
u32 GetGPR(int _step, int _gpr);
|
||||
u32 GetPC(int _step);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
OFFSET_GPR = 0x4,
|
||||
OFFSET_PC = 0x194,
|
||||
STRUCTUR_SIZE = 0x2BC
|
||||
};
|
||||
|
||||
u8 *m_pData;
|
||||
|
||||
bool m_bInit;
|
||||
size_t m_size;
|
||||
|
||||
u32 Read32(u32 _pos);
|
||||
};
|
||||
|
||||
#endif
|
109
Source/Core/Core/Src/Debugger/GCELF.h
Normal file
109
Source/Core/Core/Src/Debugger/GCELF.h
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef GCELF_H
|
||||
#define GCELF_H
|
||||
|
||||
// ELF File Types
|
||||
#define ET_NONE 0 // No file type
|
||||
#define ET_REL 1 // Relocatable file
|
||||
#define ET_EXEC 2 // Executable file
|
||||
#define ET_DYN 3 // Shared object file
|
||||
#define ET_CORE 4 // Core file
|
||||
#define ET_LOPROC 0xFF00 // Processor specific
|
||||
#define ET_HIPROC 0xFFFF // Processor specific
|
||||
|
||||
// ELF Machine Types
|
||||
#define EM_NONE 0 // No machine
|
||||
#define EM_M32 1 // AT&T WE 32100
|
||||
#define EM_SPARC 2 // SPARC
|
||||
#define EM_386 3 // Intel Architecture
|
||||
#define EM_68K 4 // Motorola 68000
|
||||
#define EM_88K 5 // Motorola 88000
|
||||
#define EM_860 6 // Intel 80860
|
||||
#define EM_MIPS 7 // MIPS RS3000 Big-Endian
|
||||
#define EM_MIPS_RS4_BE 8 // MIPS RS4000 Big-Endian
|
||||
#define EM_ARM 40 // ARM/Thumb Architecture
|
||||
|
||||
// ELF Version Types
|
||||
#define EV_NONE 0 // Invalid version
|
||||
#define EV_CURRENT 1 // Current version
|
||||
|
||||
// ELF Section Header Types
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char ID[4];
|
||||
unsigned char clazz;
|
||||
unsigned char data;
|
||||
unsigned char version;
|
||||
unsigned char pad[9];
|
||||
unsigned short e_type; // ELF file type
|
||||
unsigned short e_machine; // ELF target machine
|
||||
unsigned int e_version; // ELF file version number
|
||||
unsigned int e_entry;
|
||||
unsigned int e_phoff;
|
||||
unsigned int e_shoff;
|
||||
unsigned int e_flags;
|
||||
unsigned short e_ehsize;
|
||||
unsigned short e_phentsize;
|
||||
unsigned short e_phnum;
|
||||
unsigned short e_shentsize;
|
||||
unsigned short e_shnum;
|
||||
unsigned short e_shtrndx;
|
||||
} ELF_Header;
|
||||
|
||||
typedef struct {
|
||||
unsigned int type;
|
||||
unsigned int offset;
|
||||
unsigned int vaddr;
|
||||
unsigned int paddr;
|
||||
unsigned int filesz;
|
||||
unsigned int memsz;
|
||||
unsigned int flags;
|
||||
unsigned int align;
|
||||
} Program_Header;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int name;
|
||||
unsigned int type;
|
||||
unsigned int flags;
|
||||
unsigned int addr;
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
unsigned int link;
|
||||
unsigned int info;
|
||||
unsigned int addralign;
|
||||
unsigned int entsize;
|
||||
} Section_Header;
|
||||
|
||||
typedef struct {
|
||||
unsigned int name;
|
||||
unsigned int value;
|
||||
unsigned int size;
|
||||
unsigned char info;
|
||||
unsigned char other;
|
||||
unsigned short shndx;
|
||||
} Symbol_Header;
|
||||
|
||||
typedef struct {
|
||||
unsigned int offset;
|
||||
unsigned int info;
|
||||
signed int addend;
|
||||
} Rela_Header;
|
||||
|
||||
const char ELFID[4] = {0x7F, 'E', 'L', 'F'};
|
||||
|
||||
#endif
|
||||
|
11
Source/Core/Core/Src/Debugger/GCLibLoc.h
Normal file
11
Source/Core/Core/Src/Debugger/GCLibLoc.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _GCLIBLOC_H
|
||||
#define _GCLIBLOC_H
|
||||
|
||||
int LoadSymbolsFromO(const char* filename, unsigned int base, unsigned int count);
|
||||
|
||||
void Debugger_LoadSymbolTable(const char* _szFilename);
|
||||
void Debugger_SaveSymbolTable(const char* _szFilename);
|
||||
void Debugger_LocateSymbolTables(const char* _szFilename);
|
||||
void Debugger_ResetSymbolTables();
|
||||
|
||||
#endif
|
402
Source/Core/Core/Src/Debugger/GClibloc.cpp
Normal file
402
Source/Core/Core/Src/Debugger/GClibloc.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
//__________________________________________________________________________________________________
|
||||
//
|
||||
// GClibloc.c V1.0 by Costis!
|
||||
// (CONFIDENTIAL VERSION)
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../HLE/HLE.h"
|
||||
#include "../Host.h"
|
||||
#include "GCELF.h"
|
||||
#include "GCLibLoc.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "Debugger_SymbolMap.h"
|
||||
|
||||
|
||||
#define gELFTypeS(a) (a == ET_NONE ? "NONE" : \
|
||||
a == ET_REL ? "RELOCATABLE" : \
|
||||
a == ET_EXEC ? "EXECUTABLE" : \
|
||||
a == ET_DYN ? "SHARED OBJECT" : \
|
||||
a == ET_CORE ? "CORE" : \
|
||||
a == ET_LOPROC ? "PROCESSOR SPECIFIC: LOPROC" : \
|
||||
a == ET_HIPROC ? "PROCESSOR SPECIFIC: HIPROC" : "INVALID")
|
||||
|
||||
inline unsigned int bswap (unsigned int a)
|
||||
{
|
||||
return Common::swap32(a);
|
||||
}
|
||||
|
||||
void readSectionHeader (FILE *ifil, int section, ELF_Header ELF_H, Section_Header *ELF_SH)
|
||||
{
|
||||
fseek (ifil, ELF_H.e_shoff + ELF_H.e_shentsize * section, SEEK_SET);
|
||||
fread (ELF_SH, 1, sizeof (Section_Header), ifil);
|
||||
|
||||
// Convert the GameCube (Big Endian) format to Little Endian
|
||||
ELF_SH->name = bswap (ELF_SH->name);
|
||||
ELF_SH->type = bswap (ELF_SH->type);
|
||||
ELF_SH->flags = bswap (ELF_SH->flags);
|
||||
ELF_SH->addr = bswap (ELF_SH->addr);
|
||||
ELF_SH->offset = bswap (ELF_SH->offset);
|
||||
ELF_SH->size = bswap (ELF_SH->size);
|
||||
ELF_SH->link = bswap (ELF_SH->link);
|
||||
ELF_SH->info = bswap (ELF_SH->info);
|
||||
ELF_SH->addralign = bswap (ELF_SH->addralign);
|
||||
ELF_SH->entsize = bswap (ELF_SH->entsize);
|
||||
}
|
||||
|
||||
void readProgramHeader (FILE *ifil, int psection, ELF_Header ELF_H, Program_Header *ELF_PH)
|
||||
{
|
||||
fseek (ifil, ELF_H.e_phoff + ELF_H.e_phentsize * psection, SEEK_SET);
|
||||
fread (ELF_PH, 1, sizeof (Program_Header), ifil);
|
||||
|
||||
// Convert the GameCube (Big Endian) format to Little Endian
|
||||
ELF_PH->type = bswap (ELF_PH->type);
|
||||
ELF_PH->offset = bswap (ELF_PH->offset);
|
||||
ELF_PH->vaddr = bswap (ELF_PH->vaddr);
|
||||
ELF_PH->paddr = bswap (ELF_PH->paddr);
|
||||
ELF_PH->filesz = bswap (ELF_PH->filesz);
|
||||
ELF_PH->memsz = bswap (ELF_PH->memsz);
|
||||
ELF_PH->flags = bswap (ELF_PH->flags);
|
||||
ELF_PH->align = bswap (ELF_PH->align);
|
||||
}
|
||||
|
||||
unsigned int locShStrTab (FILE *ifil, ELF_Header ELF_H)
|
||||
{
|
||||
int i;
|
||||
Section_Header ELF_SH;
|
||||
char stID[10];
|
||||
|
||||
for (i = 1; i < ELF_H.e_shnum; i++)
|
||||
{
|
||||
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
|
||||
if (ELF_SH.type == SHT_STRTAB)
|
||||
{
|
||||
fseek (ifil, ELF_SH.offset + ELF_SH.name, SEEK_SET);
|
||||
fread (stID, 1, 10, ifil);
|
||||
if (strcmp (stID, ".shstrtab") == 0)
|
||||
return ELF_SH.offset;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned int locStrTab (FILE *ifil, ELF_Header ELF_H)
|
||||
{
|
||||
int i;
|
||||
Section_Header ELF_SH;
|
||||
unsigned int ShStrTab;
|
||||
char stID[10];
|
||||
|
||||
// Locate the Section String Table first.
|
||||
for (i = 1; i < ELF_H.e_shnum; i++)
|
||||
{
|
||||
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
|
||||
if (ELF_SH.type == SHT_STRTAB)
|
||||
{
|
||||
fseek (ifil, ELF_SH.offset + ELF_SH.name, SEEK_SET);
|
||||
fread (stID, 1, 10, ifil);
|
||||
if (strcmp (stID, ".shstrtab") == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= ELF_H.e_shnum)
|
||||
return 0; // No Section String Table was located.
|
||||
|
||||
ShStrTab = ELF_SH.offset;
|
||||
|
||||
// Locate the String Table using the Section String Table.
|
||||
for (i = 1; i < ELF_H.e_shnum; i++)
|
||||
{
|
||||
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
|
||||
if (ELF_SH.type == SHT_STRTAB)
|
||||
{
|
||||
fseek (ifil, ShStrTab + ELF_SH.name, SEEK_SET);
|
||||
fread (stID, 1, 8, ifil);
|
||||
if (strcmp (stID, ".strtab") == 0)
|
||||
return ELF_SH.offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // No String Table was located.
|
||||
}
|
||||
|
||||
unsigned int locStrTabShStrTab (FILE *ifil, unsigned int ShStrTab, ELF_Header ELF_H)
|
||||
{
|
||||
int i;
|
||||
Section_Header ELF_SH;
|
||||
char stID[8];
|
||||
|
||||
for (i = 1; i < ELF_H.e_shnum; i++)
|
||||
{
|
||||
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
|
||||
if (ELF_SH.type == SHT_STRTAB)
|
||||
{
|
||||
fseek (ifil, ShStrTab + ELF_SH.name, SEEK_SET);
|
||||
fread (stID, 1, 8, ifil);
|
||||
if (strcmp (stID, ".strtab") == 0)
|
||||
return ELF_SH.offset;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int locSection (FILE *ifil, unsigned int ShType, ELF_Header ELF_H)
|
||||
{
|
||||
int i;
|
||||
Section_Header ELF_SH;
|
||||
|
||||
for (i = 1; i < ELF_H.e_shnum; i++)
|
||||
{
|
||||
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
|
||||
if (ELF_SH.type == ShType)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int locCode (unsigned char *abuf, unsigned int fsize, unsigned char *bbuf, unsigned int offset, unsigned int size)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int b;
|
||||
|
||||
i = 0;
|
||||
while (i < fsize)
|
||||
{
|
||||
|
||||
if ((*(unsigned int*)(abuf + i)) == *(unsigned int*)(bbuf + offset))
|
||||
{
|
||||
// Code section possibly found.
|
||||
for (j = 4; j < size; j += 4)
|
||||
{
|
||||
b = (*(unsigned int*)(bbuf + offset + j));
|
||||
if ((*(unsigned int*)(abuf + i + j) != b) && (b != 0))
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= size)
|
||||
return i; // The code section was found.
|
||||
}
|
||||
i += 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int LoadSymbolsFromO(const char* filename, unsigned int base, unsigned int count)
|
||||
{
|
||||
unsigned int i, j;
|
||||
FILE *ifil;
|
||||
char astr[64];
|
||||
unsigned char *abuf, *bbuf;
|
||||
unsigned int ShStrTab, StrTab, SymTab;
|
||||
ELF_Header ELF_H;
|
||||
Section_Header ELF_SH;
|
||||
Symbol_Header ELF_SYM;
|
||||
Rela_Header ELF_RELA;
|
||||
|
||||
ifil = fopen (filename, "rb");
|
||||
if (ifil == NULL) return 0;
|
||||
|
||||
fread (&ELF_H, 1, sizeof (ELF_Header), ifil);
|
||||
ELF_H.e_type = (ELF_H.e_type >> 8) | (ELF_H.e_type << 8);
|
||||
ELF_H.e_machine = (ELF_H.e_machine >> 8) | (ELF_H.e_machine << 8);
|
||||
ELF_H.e_ehsize = (ELF_H.e_ehsize >> 8) | (ELF_H.e_ehsize << 8);
|
||||
ELF_H.e_phentsize = (ELF_H.e_phentsize >> 8) | (ELF_H.e_phentsize << 8);
|
||||
ELF_H.e_phnum = (ELF_H.e_phnum >> 8) | (ELF_H.e_phnum << 8);
|
||||
ELF_H.e_shentsize = (ELF_H.e_shentsize >> 8) | (ELF_H.e_shentsize << 8);
|
||||
ELF_H.e_shnum = (ELF_H.e_shnum >> 8) | (ELF_H.e_shnum << 8);
|
||||
ELF_H.e_shtrndx = (ELF_H.e_shtrndx >> 8) | (ELF_H.e_shtrndx << 8);
|
||||
ELF_H.e_version = bswap(ELF_H.e_version );
|
||||
ELF_H.e_entry = bswap(ELF_H.e_entry );
|
||||
ELF_H.e_phoff = bswap(ELF_H.e_phoff );
|
||||
ELF_H.e_shoff = bswap(ELF_H.e_shoff );
|
||||
ELF_H.e_flags = bswap(ELF_H.e_flags );
|
||||
|
||||
if (ELF_H.e_machine != 20)
|
||||
{
|
||||
printf ("This is not a GameCube ELF file!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf ("Identification ID: %c%c%c%c\n", ELF_H.ID[0], ELF_H.ID[1], ELF_H.ID[2], ELF_H.ID[3]);
|
||||
printf ("ELF Type: %d (%s)\n", ELF_H.e_type, gELFTypeS (ELF_H.e_type));
|
||||
printf ("ELF Machine: %d\n", ELF_H.e_machine);
|
||||
printf ("ELF Version: %d\n", ELF_H.e_version);
|
||||
|
||||
ShStrTab = locShStrTab (ifil, ELF_H);
|
||||
fseek (ifil, ShStrTab + 1, SEEK_SET);
|
||||
fread (astr, 1, 32, ifil);
|
||||
|
||||
for (i = 0; i < ELF_H.e_shnum; i++)
|
||||
{
|
||||
readSectionHeader (ifil, i, ELF_H, &ELF_SH);
|
||||
|
||||
if (ELF_SH.type != 0)
|
||||
{
|
||||
fseek (ifil, ShStrTab + ELF_SH.name, SEEK_SET);
|
||||
j = 0;
|
||||
while (1)
|
||||
if ((astr[j++] = fgetc (ifil)) == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StrTab = locStrTab (ifil, ELF_H);
|
||||
|
||||
SymTab = locSection (ifil, SHT_SYMTAB, ELF_H);
|
||||
readSectionHeader (ifil, SymTab, ELF_H, &ELF_SH);
|
||||
for (i = 1; i < ELF_SH.size / 16; i++)
|
||||
{
|
||||
fseek (ifil, ELF_SH.offset + 16 * i, SEEK_SET);
|
||||
fread (&ELF_SYM, 1, sizeof (Symbol_Header), ifil);
|
||||
ELF_SYM.name = bswap (ELF_SYM.name);
|
||||
ELF_SYM.value = bswap (ELF_SYM.value);
|
||||
ELF_SYM.size = bswap (ELF_SYM.size);
|
||||
ELF_SYM.shndx = (ELF_SYM.shndx >> 8) | (ELF_SYM.shndx << 8);
|
||||
|
||||
fseek (ifil, StrTab + ELF_SYM.name, SEEK_SET);
|
||||
j = 0;
|
||||
while (1)
|
||||
if ((astr[j++] = fgetc (ifil)) == 0) break;
|
||||
}
|
||||
|
||||
readSectionHeader (ifil, 1, ELF_H, &ELF_SH);
|
||||
fseek (ifil, ELF_SH.offset, SEEK_SET);
|
||||
if (ELF_SH.size<0 || ELF_SH.size>0x10000000)
|
||||
{
|
||||
PanicAlert("WTF??");
|
||||
}
|
||||
abuf = (unsigned char *)malloc (ELF_SH.size);
|
||||
fread (abuf, 1, ELF_SH.size, ifil);
|
||||
|
||||
//printf ("\nRelocatable Addend Header Information:\n\n");
|
||||
readSectionHeader (ifil, locSection (ifil, 4, ELF_H), ELF_H, &ELF_SH);
|
||||
|
||||
if (ELF_SH.entsize==0) //corrupt file?
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp,"Huh? ELF_SH.entsize==0 in %s!",filename);
|
||||
//MessageBox(GetForegroundWindow(),temp,"Hmm....",0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int num = ELF_SH.size / ELF_SH.entsize;
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
fseek (ifil, ELF_SH.offset + 12 * i, SEEK_SET);
|
||||
fread (&ELF_RELA, 1, sizeof (Rela_Header), ifil);
|
||||
ELF_RELA.offset = bswap (ELF_RELA.offset);
|
||||
ELF_RELA.info = bswap (ELF_RELA.info);
|
||||
ELF_RELA.addend = bswap (ELF_RELA.addend);
|
||||
|
||||
*(unsigned int*)(abuf + (ELF_RELA.offset & ~3)) = 0;
|
||||
if (ELF_SH.size == 0 || ELF_SH.entsize==0) //corrupt file?
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp,"Huh? ELF_SH.entsize==0 in %s!",filename);
|
||||
//MessageBox(GetForegroundWindow(),temp,"Hmm....",0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bbuf = (unsigned char*)Memory::GetPointer(base);
|
||||
|
||||
readSectionHeader (ifil, SymTab, ELF_H, &ELF_SH);
|
||||
for (i = 1; i < ELF_SH.size / 16; i++)
|
||||
{
|
||||
fseek (ifil, ELF_SH.offset + 16 * i, SEEK_SET);
|
||||
fread (&ELF_SYM, 1, sizeof (Symbol_Header), ifil);
|
||||
ELF_SYM.name = bswap (ELF_SYM.name);
|
||||
ELF_SYM.value = bswap (ELF_SYM.value);
|
||||
ELF_SYM.size = bswap (ELF_SYM.size);
|
||||
ELF_SYM.shndx = (ELF_SYM.shndx >> 8) | (ELF_SYM.shndx << 8);
|
||||
|
||||
if (ELF_SYM.shndx == 1)
|
||||
{
|
||||
fseek (ifil, StrTab + ELF_SYM.name, SEEK_SET);
|
||||
j = 0;
|
||||
while (1)
|
||||
{
|
||||
if ((astr[j++] = fgetc (ifil)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
u32 offset = locCode (bbuf, count, abuf, ELF_SYM.value, ELF_SYM.size);
|
||||
if (offset != 0 && ELF_SYM.size>12)
|
||||
{
|
||||
Debugger::AddSymbol(Debugger::CSymbol(offset+base | 0x80000000, ELF_SYM.size, Debugger::ST_FUNCTION, astr));
|
||||
}
|
||||
}
|
||||
}
|
||||
free (abuf);
|
||||
fclose (ifil);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Debugger_LoadSymbolTable(const char* _szFilename)
|
||||
{
|
||||
Debugger::LoadSymbolMap(_szFilename);
|
||||
HLE::PatchFunctions();
|
||||
Host_NotifyMapLoaded();
|
||||
}
|
||||
|
||||
void Debugger_SaveSymbolTable(const char* _szFilename)
|
||||
{
|
||||
Debugger::SaveSymbolMap(_szFilename);
|
||||
}
|
||||
|
||||
void Debugger_LocateSymbolTables(const char* _szFilename)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
std::string directory = _szFilename;
|
||||
const char *temp = _szFilename;
|
||||
const char *oldtemp = temp;
|
||||
temp += strlen(temp)+1;
|
||||
if (*temp==0)
|
||||
{
|
||||
//we only got one file
|
||||
files.push_back(std::string(oldtemp));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (*temp)
|
||||
{
|
||||
files.push_back(directory + _T("\\") + _T(temp));
|
||||
temp+=strlen(temp)+1;
|
||||
}
|
||||
}
|
||||
|
||||
while(!files.empty())
|
||||
{
|
||||
std::string strFilename = files.back();
|
||||
files.pop_back();
|
||||
|
||||
LOG(MASTER_LOG,"Loading symbols from %s", strFilename.c_str());
|
||||
LoadSymbolsFromO(strFilename.c_str(), 0x80000000, 24*1024*1024);
|
||||
}
|
||||
|
||||
HLE::PatchFunctions();
|
||||
}
|
||||
|
||||
|
||||
void Debugger_ResetSymbolTables()
|
||||
{
|
||||
// this shouldn't work, because we have to de-patch HLE too and that is not possible
|
||||
// Well, de-patching hle would be possible if we saved away the old code bytes :P
|
||||
// It's not like we use much HLE now anyway -ector
|
||||
Debugger::Reset();
|
||||
Host_NotifyMapLoaded();
|
||||
}
|
104
Source/Core/Core/Src/Debugger/PPCDebugInterface.cpp
Normal file
104
Source/Core/Core/Src/Debugger/PPCDebugInterface.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Debugger_BreakPoints.h"
|
||||
#include "Debugger_SymbolMap.h"
|
||||
#include "DebugInterface.h"
|
||||
#include "PPCDebugInterface.h"
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "../Core.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
// Not thread safe.
|
||||
const char *PPCDebugInterface::disasm(unsigned int address)
|
||||
{
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||
{
|
||||
if (Memory::IsRAMAddress(address))
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(address);
|
||||
return DisassembleGekko(op, address);
|
||||
}
|
||||
return "No RAM here - invalid";
|
||||
}
|
||||
|
||||
static const char tmp[] = "<unknown>";
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned int PPCDebugInterface::readMemory(unsigned int address)
|
||||
{
|
||||
return Memory::ReadUnchecked_U32(address);
|
||||
}
|
||||
|
||||
bool PPCDebugInterface::isAlive()
|
||||
{
|
||||
return Core::GetState() != Core::CORE_UNINITIALIZED;
|
||||
}
|
||||
|
||||
bool PPCDebugInterface::isBreakpoint(unsigned int address)
|
||||
{
|
||||
return CBreakPoints::IsAddressBreakPoint(address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::setBreakpoint(unsigned int address)
|
||||
{
|
||||
CBreakPoints::AddBreakPoint(address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::clearBreakpoint(unsigned int address)
|
||||
{
|
||||
CBreakPoints::RemoveBreakPoint(address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::clearAllBreakpoints() {}
|
||||
|
||||
void PPCDebugInterface::toggleBreakpoint(unsigned int address)
|
||||
{
|
||||
CBreakPoints::IsAddressBreakPoint(address)?CBreakPoints::RemoveBreakPoint(address):CBreakPoints::AddBreakPoint(address);
|
||||
}
|
||||
|
||||
int PPCDebugInterface::getColor(unsigned int address)
|
||||
{
|
||||
if (!Memory::IsRAMAddress(address))
|
||||
return 0xeeeeee;
|
||||
int colors[6] = {0xe0FFFF,0xFFe0e0,0xe8e8FF,0xFFe0FF,0xe0FFe0,0xFFFFe0};
|
||||
int n = Debugger::FindSymbol(address);
|
||||
if (n == -1) return 0xFFFFFF;
|
||||
return colors[n%6];
|
||||
}
|
||||
|
||||
std::string PPCDebugInterface::getDescription(unsigned int address)
|
||||
{
|
||||
return Debugger::GetDescription(address);
|
||||
}
|
||||
|
||||
unsigned int PPCDebugInterface::getPC()
|
||||
{
|
||||
return PowerPC::ppcState.pc;
|
||||
}
|
||||
|
||||
void PPCDebugInterface::setPC(unsigned int address)
|
||||
{
|
||||
PowerPC::ppcState.pc = address;
|
||||
}
|
||||
|
||||
void PPCDebugInterface::runToBreakpoint()
|
||||
{
|
||||
|
||||
}
|
29
Source/Core/Core/Src/Debugger/PPCDebugInterface.h
Normal file
29
Source/Core/Core/Src/Debugger/PPCDebugInterface.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _PPCDEBUGINTERFACE_H
|
||||
#define _PPCDEBUGINTERFACE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
//wrapper between disasm control and Dolphin debugger
|
||||
|
||||
class PPCDebugInterface : public DebugInterface
|
||||
{
|
||||
public:
|
||||
PPCDebugInterface(){}
|
||||
virtual const char *disasm(unsigned int address);
|
||||
virtual int getInstructionSize(int instruction) {return 4;}
|
||||
virtual bool isAlive();
|
||||
virtual bool isBreakpoint(unsigned int address);
|
||||
virtual void setBreakpoint(unsigned int address);
|
||||
virtual void clearBreakpoint(unsigned int address);
|
||||
virtual void clearAllBreakpoints();
|
||||
virtual void toggleBreakpoint(unsigned int address);
|
||||
virtual unsigned int readMemory(unsigned int address);
|
||||
virtual unsigned int getPC();
|
||||
virtual void setPC(unsigned int address);
|
||||
virtual void step() {}
|
||||
virtual void runToBreakpoint();
|
||||
virtual int getColor(unsigned int address);
|
||||
virtual std::string getDescription(unsigned int address);
|
||||
};
|
||||
|
||||
#endif
|
118
Source/Core/Core/Src/DolLoader.h
Normal file
118
Source/Core/Core/Src/DolLoader.h
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// M O D U L E B E G I N ///////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// C L A S S/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CDolLoader
|
||||
{
|
||||
public:
|
||||
|
||||
CDolLoader(const char* _szFilename) :
|
||||
m_bInit(false)
|
||||
{
|
||||
// try to open file
|
||||
FILE* pStream = NULL;
|
||||
fopen_s(&pStream, _szFilename, "rb");
|
||||
if (pStream)
|
||||
{
|
||||
fread(&m_dolheader, 1, sizeof(SDolHeader), pStream);
|
||||
|
||||
// swap memory
|
||||
DWORD* p = (DWORD*)&m_dolheader;
|
||||
for (int i=0; i<(sizeof(SDolHeader)>>2); i++)
|
||||
p[i] = Common::swap32(p[i]);
|
||||
|
||||
// load all text (code) sections
|
||||
for(int i=0; i<DOL_NUM_TEXT; i++)
|
||||
{
|
||||
if(m_dolheader.textOffset[i] != 0)
|
||||
{
|
||||
BYTE* pTemp = new BYTE[m_dolheader.textSize[i]];
|
||||
|
||||
fseek(pStream, m_dolheader.textOffset[i], SEEK_SET);
|
||||
fread(pTemp, 1, m_dolheader.textSize[i], pStream);
|
||||
|
||||
for (size_t num=0; num<m_dolheader.textSize[i]; num++)
|
||||
CMemory::Write_U8(pTemp[num], m_dolheader.textAddress[i] + num);
|
||||
|
||||
delete [] pTemp;
|
||||
}
|
||||
}
|
||||
|
||||
// load all data sections
|
||||
for(int i=0; i<DOL_NUM_DATA; i++)
|
||||
{
|
||||
if(m_dolheader.dataOffset[i] != 0)
|
||||
{
|
||||
BYTE* pTemp = new BYTE[m_dolheader.dataSize[i]];
|
||||
|
||||
fseek(pStream, m_dolheader.dataOffset[i], SEEK_SET);
|
||||
fread(pTemp, 1, m_dolheader.dataSize[i], pStream);
|
||||
|
||||
for (size_t num=0; num<m_dolheader.dataSize[i]; num++)
|
||||
CMemory::Write_U8(pTemp[num], m_dolheader.dataAddress[i] + num);
|
||||
|
||||
delete [] pTemp;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(pStream);
|
||||
m_bInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
_u32 GetEntryPoint(void)
|
||||
{
|
||||
return m_dolheader.entryPoint;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
DOL_NUM_TEXT = 7,
|
||||
DOL_NUM_DATA = 11
|
||||
};
|
||||
|
||||
struct SDolHeader
|
||||
{
|
||||
_u32 textOffset[DOL_NUM_TEXT];
|
||||
_u32 dataOffset[DOL_NUM_DATA];
|
||||
|
||||
_u32 textAddress[DOL_NUM_TEXT];
|
||||
_u32 dataAddress[DOL_NUM_DATA];
|
||||
|
||||
_u32 textSize[DOL_NUM_TEXT];
|
||||
_u32 dataSize[DOL_NUM_DATA];
|
||||
|
||||
_u32 bssAddress;
|
||||
_u32 bssSize;
|
||||
_u32 entryPoint;
|
||||
_u32 padd[7];
|
||||
};
|
||||
|
||||
SDolHeader m_dolheader;
|
||||
|
||||
bool m_bInit;
|
||||
};
|
122
Source/Core/Core/Src/HLE/HLE.cpp
Normal file
122
Source/Core/Core/Src/HLE/HLE.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "HLE.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "../Debugger/Debugger_SymbolMap.h"
|
||||
#include "../Debugger/Debugger_BreakPoints.h"
|
||||
|
||||
#include "HLE_OS.h"
|
||||
#include "HLE_Misc.h"
|
||||
|
||||
namespace HLE
|
||||
{
|
||||
|
||||
using namespace PowerPC;
|
||||
|
||||
typedef void (*TPatchFunction)();
|
||||
|
||||
enum
|
||||
{
|
||||
HLE_RETURNTYPE_BLR = 0,
|
||||
HLE_RETURNTYPE_RFI = 1,
|
||||
};
|
||||
|
||||
struct SPatch
|
||||
{
|
||||
char m_szPatchName[128];
|
||||
TPatchFunction PatchFunction;
|
||||
int returnType;
|
||||
};
|
||||
|
||||
SPatch OSPatches[] =
|
||||
{
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||
|
||||
// speedup
|
||||
{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse },
|
||||
// { "THPPlayerGetState", HLE_Misc:THPPlayerGetState },
|
||||
|
||||
|
||||
// Debugout is very nice .)
|
||||
{ "OSReport", HLE_OS::HLE_OSReport },
|
||||
{ "OSPanic", HLE_OS::HLE_OSPanic },
|
||||
{ "vprintf", HLE_OS::HLE_vprintf },
|
||||
{ "printf", HLE_OS::HLE_printf },
|
||||
|
||||
// wii only
|
||||
{ "SCCheckStatus", HLE_Misc::UnimplementedFunctionFalse }, // SC is SystemConfig ... dunn
|
||||
|
||||
// special
|
||||
// { "GXPeekZ", HLE_Misc::GXPeekZ},
|
||||
// { "GXPeekARGB", HLE_Misc::GXPeekARGB},
|
||||
};
|
||||
|
||||
SPatch OSBreakPoints[] =
|
||||
{
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||
//{ "__OSInitAudioSystem", CHLE_Audio::__OSInitAudioSystem },
|
||||
};
|
||||
|
||||
void PatchFunctions(const char* _gameID)
|
||||
{
|
||||
for (u32 i=0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
||||
{
|
||||
int SymbolIndex = Debugger::FindSymbol(OSPatches[i].m_szPatchName);
|
||||
if (SymbolIndex > 0)
|
||||
{
|
||||
const Debugger::CSymbol& rSymbol = Debugger::GetSymbol(SymbolIndex);
|
||||
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
||||
Memory::Write_U32(HLEPatchValue | i, rSymbol.vaddress);
|
||||
|
||||
LOG(HLE,"Patching %s %08x", OSPatches[i].m_szPatchName, rSymbol.vaddress);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i=1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
|
||||
{
|
||||
int SymbolIndex = Debugger::FindSymbol(OSBreakPoints[i].m_szPatchName);
|
||||
if (SymbolIndex != -1)
|
||||
{
|
||||
const Debugger::CSymbol& rSymbol = Debugger::GetSymbol(SymbolIndex);
|
||||
CBreakPoints::AddBreakPoint(rSymbol.vaddress, false);
|
||||
|
||||
LOG(HLE,"Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, rSymbol.vaddress);
|
||||
}
|
||||
}
|
||||
|
||||
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
|
||||
}
|
||||
|
||||
void Execute(u32 _CurrentPC, u32 _Instruction)
|
||||
{
|
||||
int FunctionIndex = _Instruction & 0xFFFFF;
|
||||
if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch))))
|
||||
{
|
||||
OSPatches[FunctionIndex].PatchFunction();
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg_assert_(HLE, 0);
|
||||
}
|
||||
|
||||
// _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", OSPatches[pos].m_szPatchName);
|
||||
}
|
||||
|
||||
}
|
30
Source/Core/Core/Src/HLE/HLE.h
Normal file
30
Source/Core/Core/Src/HLE/HLE.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _HLE_H
|
||||
#define _HLE_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace HLE
|
||||
{
|
||||
void PatchFunctions(const char* _gameID = 0);
|
||||
void Execute(u32 _CurrentPC, u32 _Instruction);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
61
Source/Core/Core/Src/HLE/HLE_Misc.cpp
Normal file
61
Source/Core/Core/Src/HLE/HLE_Misc.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "HLE_OS.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../HW/Memmap.h"
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
|
||||
void UnimplementedFunction()
|
||||
{
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void UnimplementedFunctionTrue()
|
||||
{
|
||||
GPR(3)=1;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void UnimplementedFunctionFalse()
|
||||
{
|
||||
GPR(3)=0;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void THPPlayerGetState()
|
||||
{
|
||||
GPR(3)=3; // Video played
|
||||
NPC=LR;
|
||||
}
|
||||
|
||||
void GXPeekZ()
|
||||
{
|
||||
Memory::Write_U32(0xFFFFFF,GPR(5));
|
||||
NPC=LR;
|
||||
}
|
||||
|
||||
void GXPeekARGB()
|
||||
{
|
||||
Memory::Write_U32(0xFFFFFFFF,GPR(5));
|
||||
NPC=LR;
|
||||
}
|
||||
|
||||
}
|
32
Source/Core/Core/Src/HLE/HLE_Misc.h
Normal file
32
Source/Core/Core/Src/HLE/HLE_Misc.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef HLE_MISC_H
|
||||
#define HLE_MISC_H
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
void Pass();
|
||||
void UnimplementedFunction();
|
||||
void UnimplementedFunctionTrue();
|
||||
void UnimplementedFunctionFalse();
|
||||
void THPPlayerGetState();
|
||||
void GXPeekZ();
|
||||
void GXPeekARGB();
|
||||
}
|
||||
|
||||
#endif
|
127
Source/Core/Core/Src/HLE/HLE_OS.cpp
Normal file
127
Source/Core/Core/Src/HLE/HLE_OS.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "StringUtil.h"
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include "HLE_OS.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../HW/Memmap.h"
|
||||
|
||||
namespace HLE_OS
|
||||
{
|
||||
|
||||
void GetStringVA(std::string& _rOutBuffer);
|
||||
|
||||
void HLE_OSPanic()
|
||||
{
|
||||
std::string Error;
|
||||
GetStringVA(Error);
|
||||
|
||||
PanicAlert("PanicAlert: %s", Error.c_str());
|
||||
LOG(HLE,"(PC=%08x), PanicAlert: %s", LR, Error.c_str());
|
||||
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void HLE_OSReport()
|
||||
{
|
||||
std::string ReportMessage;
|
||||
GetStringVA(ReportMessage);
|
||||
|
||||
LOG(HLE,"(PC=%08x) OSReport: %s", LR, ReportMessage.c_str());
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void HLE_vprintf()
|
||||
{
|
||||
std::string ReportMessage;
|
||||
GetStringVA(ReportMessage);
|
||||
|
||||
LOG(HLE,"(PC=%08x) VPrintf: %s", LR, ReportMessage.c_str());
|
||||
NPC = LR;
|
||||
|
||||
}
|
||||
|
||||
void HLE_printf()
|
||||
{
|
||||
std::string ReportMessage;
|
||||
GetStringVA(ReportMessage);
|
||||
|
||||
LOG(HLE,"(PC=%08x) Printf: %s ", LR, ReportMessage.c_str());
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void GetStringVA(std::string& _rOutBuffer)
|
||||
{
|
||||
char ArgumentBuffer[256];
|
||||
u32 ParameterCounter = 4;
|
||||
char* pString = (char*)Memory::GetPointer(GPR(3));
|
||||
|
||||
while(*pString)
|
||||
{
|
||||
if (*pString == '%')
|
||||
{
|
||||
char* pArgument = ArgumentBuffer;
|
||||
*pArgument++ = *pString++;
|
||||
while(*pString < 'A' || *pString > 'z' || *pString == 'l' || *pString == '-')
|
||||
*pArgument++ = *pString++;
|
||||
|
||||
*pArgument++ = *pString;
|
||||
*pArgument = NULL;
|
||||
|
||||
u32 Parameter;
|
||||
if (ParameterCounter > 10)
|
||||
{
|
||||
Parameter = Memory::Read_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
Parameter = GPR(ParameterCounter);
|
||||
}
|
||||
ParameterCounter++;
|
||||
|
||||
switch(*pString)
|
||||
{
|
||||
case 's':
|
||||
_rOutBuffer += StringFromFormat(ArgumentBuffer, (char*)Memory::GetPointer(Parameter));
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
{
|
||||
//u64 Double = Memory::Read_U64(Parameter);
|
||||
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_rOutBuffer += StringFromFormat(ArgumentBuffer, Parameter);
|
||||
break;
|
||||
}
|
||||
pString++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rOutBuffer += StringFromFormat("%c", *pString);
|
||||
pString++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
31
Source/Core/Core/Src/HLE/HLE_OS.h
Normal file
31
Source/Core/Core/Src/HLE/HLE_OS.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef HLE_OS_H
|
||||
#define HLE_OS_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace HLE_OS
|
||||
{
|
||||
void HLE_vprintf();
|
||||
void HLE_printf();
|
||||
void HLE_OSReport();
|
||||
void HLE_OSPanic();
|
||||
}
|
||||
|
||||
#endif
|
329
Source/Core/Core/Src/HW/AudioInterface.cpp
Normal file
329
Source/Core/Core/Src/HW/AudioInterface.cpp
Normal file
@ -0,0 +1,329 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "StreamADPCM.H"
|
||||
#include "AudioInterface.h"
|
||||
|
||||
#include "CPU.h"
|
||||
#include "PeripheralInterface.h"
|
||||
#include "DVDInterface.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../CoreTiming.h"
|
||||
#include "../HW/SystemTimers.h"
|
||||
|
||||
namespace AudioInterface
|
||||
{
|
||||
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
AI_CONTROL_REGISTER = 0x6C00,
|
||||
AI_VOLUME_REGISTER = 0x6C04,
|
||||
AI_SAMPLE_COUNTER = 0x6C08,
|
||||
AI_INTERRUPT_TIMING = 0x6C0C,
|
||||
};
|
||||
|
||||
// AI Control Register
|
||||
union AICR
|
||||
{
|
||||
AICR() { hex = 0;}
|
||||
AICR(u32 _hex) { hex = _hex;}
|
||||
struct
|
||||
{
|
||||
unsigned PSTAT : 1; // sample counter/playback enable
|
||||
unsigned AFR : 1; // 0=32khz 1=48khz
|
||||
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
|
||||
unsigned AIINT : 1; // audio interrupt status
|
||||
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
|
||||
// matching AISLRCNT. Once set, AIINT will hold
|
||||
unsigned SCRESET : 1; // write to reset counter
|
||||
unsigned DSPFR : 1; // DSP Frequency (0=32khz 1=48khz)
|
||||
unsigned :25;
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
// AI m_Volume Register
|
||||
union AIVR
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned leftVolume : 8;
|
||||
unsigned rightVolume : 8;
|
||||
unsigned : 16;
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
// AudioInterface-Registers
|
||||
struct SAudioRegister
|
||||
{
|
||||
AICR m_Control;
|
||||
AIVR m_Volume;
|
||||
u32 m_SampleCounter;
|
||||
u32 m_InterruptTiming;
|
||||
};
|
||||
|
||||
SAudioRegister g_AudioRegister;
|
||||
|
||||
void GenerateAudioInterrupt();
|
||||
void UpdateInterrupts();
|
||||
void IncreaseSampleCount(const u32 _uAmount);
|
||||
void ReadStreamBlock(short* _pPCM);
|
||||
|
||||
static u64 g_LastCPUTime = 0;
|
||||
static int g_SampleRate = 32000;
|
||||
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
|
||||
|
||||
void Init()
|
||||
{
|
||||
g_AudioRegister.m_SampleCounter = 0;
|
||||
g_AudioRegister.m_Control.AFR = 1;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
//__AI_SRC_INIT compares CC006C08 to zero, loops if 2
|
||||
switch (_Address & 0xFFFF)
|
||||
{
|
||||
case AI_CONTROL_REGISTER: //0x6C00
|
||||
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
||||
_rReturnValue = g_AudioRegister.m_Control.hex;
|
||||
return;
|
||||
|
||||
// Sample Rate (AIGetDSPSampleRate)
|
||||
// 32bit state (highest bit PlayState) // AIGetStreamPlayState
|
||||
case AI_VOLUME_REGISTER: //0x6C04
|
||||
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
||||
_rReturnValue = g_AudioRegister.m_Volume.hex;
|
||||
return;
|
||||
|
||||
case AI_SAMPLE_COUNTER: //0x6C08
|
||||
_rReturnValue = g_AudioRegister.m_SampleCounter;
|
||||
if (g_AudioRegister.m_Control.PSTAT)
|
||||
g_AudioRegister.m_SampleCounter++; // FAKE: but this is a must
|
||||
return;
|
||||
|
||||
case AI_INTERRUPT_TIMING:
|
||||
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
||||
_rReturnValue = g_AudioRegister.m_InterruptTiming;
|
||||
return;
|
||||
|
||||
default:
|
||||
LOG(AUDIO_INTERFACE, "AudioInterface(R) 0x%08x", _Address);
|
||||
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Read from ???");
|
||||
_rReturnValue = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Write32(const u32 _Value, const u32 _Address)
|
||||
{
|
||||
switch (_Address & 0xFFFF)
|
||||
{
|
||||
case AI_CONTROL_REGISTER:
|
||||
{
|
||||
AICR tmpAICtrl(_Value);
|
||||
|
||||
g_AudioRegister.m_Control.AIINTMSK = tmpAICtrl.AIINTMSK;
|
||||
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
|
||||
|
||||
// Set frequency
|
||||
if (tmpAICtrl.AFR != g_AudioRegister.m_Control.AFR)
|
||||
{
|
||||
LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AFR ? "48khz":"32khz");
|
||||
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
|
||||
}
|
||||
|
||||
g_SampleRate = g_AudioRegister.m_Control.AFR ? 48000 : 32000;
|
||||
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
|
||||
|
||||
// Streaming counter
|
||||
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
|
||||
{
|
||||
LOG(AUDIO_INTERFACE, "Change StreamingCounter to %s", tmpAICtrl.PSTAT ? "startet":"stopped");
|
||||
g_AudioRegister.m_Control.PSTAT = tmpAICtrl.PSTAT;
|
||||
|
||||
g_LastCPUTime = CoreTiming::GetTicks();
|
||||
}
|
||||
|
||||
// AI Interrupt
|
||||
if (tmpAICtrl.AIINT)
|
||||
{
|
||||
LOG(AUDIO_INTERFACE, "Clear AI Interrupt");
|
||||
g_AudioRegister.m_Control.AIINT = 0;
|
||||
}
|
||||
|
||||
// Sample Count Reset
|
||||
if (tmpAICtrl.SCRESET)
|
||||
{
|
||||
LOG(AUDIO_INTERFACE, "Reset SampleCounter");
|
||||
g_AudioRegister.m_SampleCounter = 0;
|
||||
g_AudioRegister.m_Control.SCRESET = 0;
|
||||
|
||||
// set PSTAT = 0 too ? at least the reversed look like this
|
||||
|
||||
g_LastCPUTime = CoreTiming::GetTicks();
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
|
||||
case AI_VOLUME_REGISTER:
|
||||
g_AudioRegister.m_Volume.hex = _Value;
|
||||
LOG(AUDIO_INTERFACE, "Set m_Volume: left(%i) right(%i)", g_AudioRegister.m_Volume.leftVolume, g_AudioRegister.m_Volume.rightVolume);
|
||||
break;
|
||||
|
||||
case AI_SAMPLE_COUNTER:
|
||||
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - m_SampleCounter is Read only");
|
||||
break;
|
||||
|
||||
case AI_INTERRUPT_TIMING:
|
||||
g_AudioRegister.m_InterruptTiming = _Value;
|
||||
LOG(AUDIO_INTERFACE, "Set AudioInterrupt: 0x%08x Samples", g_AudioRegister.m_InterruptTiming);
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlert("AudioInterface unknown write");
|
||||
_dbg_assert_msg_(AUDIO_INTERFACE,0,"AudioInterface - Write to ??? %08x", _Address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
if (g_AudioRegister.m_Control.AIINT & g_AudioRegister.m_Control.AIINTMSK)
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_AUDIO, false);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateAudioInterrupt()
|
||||
{
|
||||
g_AudioRegister.m_Control.AIINT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
// Callback for the DSP streaming
|
||||
// WARNING - called from audio thread
|
||||
unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples)
|
||||
{
|
||||
if (g_AudioRegister.m_Control.PSTAT && !CCPU::IsStepping())
|
||||
{
|
||||
static int pos = 0;
|
||||
static short pcm[28*2];
|
||||
const int lvolume = g_AudioRegister.m_Volume.leftVolume;
|
||||
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
|
||||
|
||||
for (unsigned int i=0; i<_numSamples; i++)
|
||||
{
|
||||
if (pos==0)
|
||||
{
|
||||
ReadStreamBlock(pcm);
|
||||
}
|
||||
|
||||
*_pDestBuffer++ = (pcm[pos*2] * lvolume) >> 8;
|
||||
*_pDestBuffer++ = (pcm[pos*2+1] * rvolume) >> 8;
|
||||
|
||||
pos++;
|
||||
if (pos == 28)
|
||||
{
|
||||
pos=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i=0; i<_numSamples*2; i++)
|
||||
{
|
||||
_pDestBuffer[i] = 0; //silence!
|
||||
}
|
||||
}
|
||||
|
||||
return _numSamples;
|
||||
}
|
||||
|
||||
// WARNING - called from audio thread
|
||||
void ReadStreamBlock(short* _pPCM)
|
||||
{
|
||||
char tempADPCM[32];
|
||||
if (DVDInterface::DVDReadADPCM((u8*)tempADPCM, 32))
|
||||
{
|
||||
NGCADPCM::DecodeBlock(_pPCM, (u8*)tempADPCM);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j=0; j<28; j++)
|
||||
{
|
||||
*_pPCM++ = 0;
|
||||
*_pPCM++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// COMMENT:
|
||||
// our whole streaming code is "faked" ... so it shouldn't increase the sample counter
|
||||
// streaming will never work correctly this way, but at least the program will think all is alright.
|
||||
|
||||
// IncreaseSampleCount(28);
|
||||
}
|
||||
|
||||
void IncreaseSampleCount(const u32 _iAmount)
|
||||
{
|
||||
if (g_AudioRegister.m_Control.PSTAT)
|
||||
{
|
||||
g_AudioRegister.m_SampleCounter += _iAmount;
|
||||
if (g_AudioRegister.m_Control.AIINTVLD &&
|
||||
(g_AudioRegister.m_SampleCounter > g_AudioRegister.m_InterruptTiming))
|
||||
{
|
||||
GenerateAudioInterrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetRate()
|
||||
{
|
||||
return g_SampleRate;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// update timer
|
||||
if (g_AudioRegister.m_Control.PSTAT)
|
||||
{
|
||||
const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime;
|
||||
if (Diff > g_CPUCyclesPerSample)
|
||||
{
|
||||
const u32 Samples = static_cast<u32>(Diff / g_CPUCyclesPerSample);
|
||||
g_LastCPUTime += Samples * g_CPUCyclesPerSample;
|
||||
IncreaseSampleCount(Samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace AudioInterface
|
||||
|
47
Source/Core/Core/Src/HW/AudioInterface.h
Normal file
47
Source/Core/Core/Src/HW/AudioInterface.h
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _AUDIOINTERFACE_H
|
||||
#define _AUDIOINTERFACE_H
|
||||
|
||||
namespace AudioInterface
|
||||
{
|
||||
|
||||
// Init
|
||||
void Init();
|
||||
|
||||
// Shutdown
|
||||
void Shutdown();
|
||||
|
||||
// Update
|
||||
void Update();
|
||||
|
||||
// Calls by DSP plugin
|
||||
unsigned __int32 Callback_GetStreaming(short* _pDestBuffer, unsigned __int32 _numSamples);
|
||||
|
||||
// Read32
|
||||
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||
|
||||
// Write32
|
||||
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
|
||||
|
||||
// Get the Audio Rate (48000 or 32000)
|
||||
u32 GetRate();
|
||||
|
||||
} // end of namespace AudioInterface
|
||||
|
||||
#endif
|
||||
|
237
Source/Core/Core/Src/HW/CPU.cpp
Normal file
237
Source/Core/Core/Src/HW/CPU.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../Host.h"
|
||||
#include "../Core.h"
|
||||
#include "CPU.h"
|
||||
#include "CPUCompare.h"
|
||||
|
||||
#include "../Debugger/Debugger_BreakPoints.h"
|
||||
|
||||
using namespace PowerPC;
|
||||
namespace {
|
||||
bool g_Branch;
|
||||
Common::Event m_StepEvent;
|
||||
Common::Event *m_SyncEvent;
|
||||
}
|
||||
|
||||
void CCPU::Init()
|
||||
{
|
||||
m_StepEvent.Init();
|
||||
PowerPC::Init();
|
||||
m_SyncEvent = 0;
|
||||
}
|
||||
|
||||
void CCPU::Shutdown()
|
||||
{
|
||||
PowerPC::Shutdown();
|
||||
m_StepEvent.Shutdown();
|
||||
m_SyncEvent = 0;
|
||||
}
|
||||
|
||||
void CCPU::Run()
|
||||
{
|
||||
Host_UpdateDisasmDialog();
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch(PowerPC::state) {
|
||||
case CPU_RUNNING:
|
||||
//1: enter a fast runloop
|
||||
PowerPC::RunLoop();
|
||||
break;
|
||||
|
||||
case CPU_RUNNINGDEBUG:
|
||||
//1: check for cpucompare
|
||||
/*
|
||||
if (CPUCompare::IsEnabled() && g_Branch)
|
||||
{
|
||||
g_Branch = false;
|
||||
CPUCompare::Sync();
|
||||
}*/
|
||||
|
||||
//2: check for breakpoint
|
||||
if (CBreakPoints::IsAddressBreakPoint(PC))
|
||||
{
|
||||
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
|
||||
EnableStepping(true);
|
||||
if (CBreakPoints::IsTempBreakPoint(PC))
|
||||
CBreakPoints::RemoveBreakPoint(PC);
|
||||
|
||||
Host_UpdateDisasmDialog();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* if (!Core::g_CoreStartupParameter.bUseDynarec && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
|
||||
{
|
||||
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
|
||||
EnableStepping(true);
|
||||
break;
|
||||
}*/
|
||||
|
||||
//3: do a step
|
||||
PowerPC::SingleStep();
|
||||
break;
|
||||
|
||||
case CPU_STEPPING:
|
||||
//1: wait for step command..
|
||||
|
||||
m_StepEvent.Wait();
|
||||
if (state == CPU_POWERDOWN)
|
||||
return;
|
||||
|
||||
//2: check for cpu compare
|
||||
if (CPUCompare::IsEnabled() && g_Branch)
|
||||
{
|
||||
g_Branch = false;
|
||||
CPUCompare::Sync();
|
||||
}
|
||||
|
||||
//3: do a step
|
||||
PowerPC::SingleStep();
|
||||
|
||||
//4: update disasm dialog
|
||||
if (m_SyncEvent) {
|
||||
m_SyncEvent->Set();
|
||||
m_SyncEvent = 0;
|
||||
}
|
||||
Host_UpdateDisasmDialog();
|
||||
break;
|
||||
|
||||
case CPU_POWERDOWN:
|
||||
//1: Exit loop!!
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCPU::Stop()
|
||||
{
|
||||
PowerPC::Stop();
|
||||
m_StepEvent.Set();
|
||||
}
|
||||
|
||||
bool CCPU::IsStepping()
|
||||
{
|
||||
return PowerPC::state == CPU_STEPPING;
|
||||
}
|
||||
|
||||
void CCPU::Reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CCPU::StepOpcode(Common::Event *event)
|
||||
{
|
||||
m_StepEvent.Set();
|
||||
if (PowerPC::state == CPU_STEPPING)
|
||||
{
|
||||
m_SyncEvent = event;
|
||||
}
|
||||
}
|
||||
|
||||
void CCPU::EnableStepping(const bool _bStepping)
|
||||
{
|
||||
if (_bStepping)
|
||||
{
|
||||
PowerPC::Pause();
|
||||
// TODO(ector): why a sleep?
|
||||
Host_SetDebugMode(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host_SetDebugMode(false);
|
||||
PowerPC::Start();
|
||||
m_StepEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
void CCPU::SingleStep()
|
||||
{
|
||||
switch (PowerPC::state)
|
||||
{
|
||||
case CPU_RUNNING:
|
||||
//1: enter a fast runloop
|
||||
PowerPC::RunLoop();
|
||||
break;
|
||||
|
||||
case CPU_RUNNINGDEBUG:
|
||||
//1: check for cpucompare
|
||||
if (CPUCompare::IsEnabled() && g_Branch)
|
||||
{
|
||||
g_Branch = false;
|
||||
CPUCompare::Sync();
|
||||
}
|
||||
|
||||
//2: check for breakpoint
|
||||
if (CBreakPoints::IsAddressBreakPoint(PC))
|
||||
{
|
||||
LOG(GEKKO, "Hit Breakpoint - %08x", PC);
|
||||
EnableStepping(true);
|
||||
if (CBreakPoints::IsTempBreakPoint(PC))
|
||||
CBreakPoints::RemoveBreakPoint(PC);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Core::g_CoreStartupParameter.bUseDynarec && CBreakPoints::GetBreakCount() == PowerPC::ppcState.DebugCount)
|
||||
{
|
||||
LOG(GEKKO, "Hit DebugCount breakpoint - %i", PowerPC::ppcState.DebugCount);
|
||||
EnableStepping(true);
|
||||
break;
|
||||
}
|
||||
|
||||
//3: do a step
|
||||
PowerPC::SingleStep();
|
||||
break;
|
||||
|
||||
case CPU_STEPPING:
|
||||
//1: wait for step command..
|
||||
m_StepEvent.Wait();
|
||||
|
||||
//2: check for cpu compare
|
||||
if (CPUCompare::IsEnabled() && g_Branch)
|
||||
{
|
||||
g_Branch = false;
|
||||
CPUCompare::Sync();
|
||||
}
|
||||
|
||||
//3: do a step
|
||||
PowerPC::SingleStep();
|
||||
|
||||
//4: update disasm dialog
|
||||
if (m_SyncEvent) {
|
||||
m_SyncEvent->Set();
|
||||
m_SyncEvent = 0;
|
||||
}
|
||||
Host_UpdateDisasmDialog();
|
||||
break;
|
||||
|
||||
case CPU_POWERDOWN:
|
||||
//1: Exit loop!!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CCPU::Break()
|
||||
{
|
||||
EnableStepping(true);
|
||||
}
|
60
Source/Core/Core/Src/HW/CPU.h
Normal file
60
Source/Core/Core/Src/HW/CPU.h
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _CPU_H
|
||||
#define _CPU_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace Common {
|
||||
class Event;
|
||||
}
|
||||
|
||||
class CCPU
|
||||
{
|
||||
public:
|
||||
// init
|
||||
static void Init();
|
||||
|
||||
// shutdown
|
||||
static void Shutdown();
|
||||
|
||||
// starts the CPU
|
||||
static void Run();
|
||||
|
||||
// causes shutdown
|
||||
static void Stop();
|
||||
// Reset
|
||||
static void Reset();
|
||||
|
||||
// StepOpcode (Steps one Opcode)
|
||||
static void StepOpcode(Common::Event *event = 0);
|
||||
|
||||
// one step only
|
||||
static void SingleStep();
|
||||
|
||||
// Enable or Disable Stepping
|
||||
static void EnableStepping(const bool _bStepping);
|
||||
|
||||
// is stepping ?
|
||||
static bool IsStepping();
|
||||
|
||||
// break
|
||||
static void Break();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
246
Source/Core/Core/Src/HW/CPUCompare.cpp
Normal file
246
Source/Core/Core/Src/HW/CPUCompare.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "../Core.h"
|
||||
|
||||
#include "CPUCompare.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "CommandProcessor.h"
|
||||
|
||||
|
||||
#include "../Host.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace CPUCompare
|
||||
{
|
||||
|
||||
HANDLE m_hPipe;
|
||||
bool m_bIsServer;
|
||||
bool m_bEnabled;
|
||||
u32 m_BlockStart;
|
||||
|
||||
#define PIPENAME "\\\\.\\pipe\\cpucompare"
|
||||
|
||||
|
||||
int stateSize = 32*4 + 32*16 + 6*4;
|
||||
|
||||
|
||||
void SetBlockStart(u32 addr)
|
||||
{
|
||||
m_BlockStart = addr;
|
||||
}
|
||||
|
||||
void StartServer()
|
||||
{
|
||||
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
|
||||
|
||||
if (m_bEnabled)
|
||||
return;
|
||||
//TODO: error checking
|
||||
m_hPipe = CreateNamedPipe(
|
||||
PIPENAME,
|
||||
PIPE_ACCESS_OUTBOUND,
|
||||
PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
|
||||
1, //maxinst
|
||||
0x1000, //outbufsize
|
||||
0x1000, //inbufsize
|
||||
INFINITE, //timeout
|
||||
0);
|
||||
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to create pipe.");
|
||||
//_assert_msg_(GEKKO, 0, "Pipe %s created.", PIPENAME);
|
||||
|
||||
m_bIsServer = true;
|
||||
m_bEnabled = true;
|
||||
}
|
||||
|
||||
void ConnectAsClient()
|
||||
{
|
||||
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
|
||||
|
||||
if (m_bEnabled)
|
||||
return;
|
||||
|
||||
//TODO: error checking
|
||||
m_hPipe = CreateFile(
|
||||
PIPENAME,
|
||||
GENERIC_READ,
|
||||
0, //share
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to connect to pipe. %08x (2 = file not found)", GetLastError());
|
||||
|
||||
m_bEnabled = true;
|
||||
m_bIsServer = false;
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
if (m_bEnabled)
|
||||
{
|
||||
if (m_bIsServer)
|
||||
{
|
||||
DisconnectNamedPipe(m_hPipe);
|
||||
CloseHandle(m_hPipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseHandle(m_hPipe); //both for server and client i guess
|
||||
}
|
||||
m_bEnabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
int Sync()
|
||||
{
|
||||
_assert_msg_(GEKKO,0,"Sync - PC = %08x", PC);
|
||||
|
||||
PowerPC::PowerPCState state;
|
||||
if (!m_bEnabled)
|
||||
return 0;
|
||||
|
||||
if (m_bIsServer) //This should be interpreter
|
||||
{
|
||||
//write cpu state to m_hPipe
|
||||
HRESULT result;
|
||||
u32 written;
|
||||
// LogManager::Redraw();
|
||||
result = WriteFile(m_hPipe, &PowerPC::ppcState, stateSize, (LPDWORD)&written,FALSE);
|
||||
//_assert_msg_(GEKKO, 0, "Server Wrote!");
|
||||
if (FAILED(result))
|
||||
{
|
||||
_assert_msg_(GEKKO,0,"Failed to write cpu state to named pipe");
|
||||
Stop();
|
||||
}
|
||||
// LogManager::Redraw();
|
||||
}
|
||||
else //This should be dynarec
|
||||
{
|
||||
u32 read;
|
||||
memset(&state,0xcc,stateSize);
|
||||
BOOL res = ReadFile(m_hPipe, &state, stateSize, (LPDWORD)&read, FALSE);
|
||||
//_assert_msg_(GEKKO, 0, "Client got data!");
|
||||
|
||||
//read cpu state to m_hPipe and compare
|
||||
//if any errors, print report
|
||||
if (!res || read != stateSize)
|
||||
{
|
||||
_assert_msg_(GEKKO,0,"Failed to read cpu state from named pipe");
|
||||
Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool difference = false;
|
||||
for (int i=0; i<32; i++)
|
||||
{
|
||||
if (PowerPC::ppcState.gpr[i] != state.gpr[i])
|
||||
{
|
||||
LOG(GEKKO, "DIFFERENCE - r%i (local %08x, remote %08x)", i, PowerPC::ppcState.gpr[i], state.gpr[i]);
|
||||
difference = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<32; i++)
|
||||
{
|
||||
for (int j=0; j<2; j++)
|
||||
{
|
||||
if (PowerPC::ppcState.ps[i][j] != state.ps[i][j])
|
||||
{
|
||||
LOG(GEKKO, "DIFFERENCE - ps%i_%i (local %f, remote %f)", i, j, PowerPC::ppcState.ps[i][j], state.ps[i][j]);
|
||||
difference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PowerPC::ppcState.cr != state.cr)
|
||||
{
|
||||
LOG(GEKKO, "DIFFERENCE - CR (local %08x, remote %08x)", PowerPC::ppcState.cr, state.cr);
|
||||
difference = true;
|
||||
}
|
||||
if (PowerPC::ppcState.pc != state.pc)
|
||||
{
|
||||
LOG(GEKKO, "DIFFERENCE - PC (local %08x, remote %08x)", PowerPC::ppcState.pc, state.pc);
|
||||
difference = true;
|
||||
}
|
||||
//if (PowerPC::ppcState.npc != state.npc)
|
||||
///{
|
||||
// LOG(GEKKO, "DIFFERENCE - NPC (local %08x, remote %08x)", PowerPC::ppcState.npc, state.npc);
|
||||
// difference = true;
|
||||
//}
|
||||
if (PowerPC::ppcState.msr != state.msr)
|
||||
{
|
||||
LOG(GEKKO, "DIFFERENCE - MSR (local %08x, remote %08x)", PowerPC::ppcState.msr, state.msr);
|
||||
difference = true;
|
||||
}
|
||||
if (PowerPC::ppcState.fpscr != state.fpscr)
|
||||
{
|
||||
LOG(GEKKO, "DIFFERENCE - FPSCR (local %08x, remote %08x)", PowerPC::ppcState.fpscr, state.fpscr);
|
||||
difference = true;
|
||||
}
|
||||
|
||||
if (difference)
|
||||
{
|
||||
Host_UpdateLogDisplay();
|
||||
//Also show drec compare window here
|
||||
//CDynaViewDlg::Show(true);
|
||||
//CDynaViewDlg::ViewAddr(m_BlockStart);
|
||||
//CDynaViewDlg::Show(true);
|
||||
//Sleep(INFINITE);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
//LOG(GEKKO, "No difference!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IsEnabled()
|
||||
{
|
||||
return m_bEnabled;
|
||||
}
|
||||
|
||||
bool IsServer()
|
||||
{
|
||||
return m_bIsServer;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#else
|
||||
|
||||
namespace CPUCompare
|
||||
{
|
||||
void StartServer() { }
|
||||
void ConnectAsClient() { }
|
||||
void Stop() { }
|
||||
int Sync() { return 0; }
|
||||
bool IsEnabled() { return false; }
|
||||
bool IsServer() { return false; }
|
||||
}
|
||||
// #error Provide a CPUCompare implementation or dummy it out, please
|
||||
|
||||
#endif
|
50
Source/Core/Core/Src/HW/CPUCompare.h
Normal file
50
Source/Core/Core/Src/HW/CPUCompare.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Sets up and maintains interprocess communication to make it possible
|
||||
// to easily compare any two cpu cores by running two instances of DolphinHLE and
|
||||
// comparing them to each other.
|
||||
//
|
||||
|
||||
#ifndef _CPUCOMPARE_H
|
||||
#define _CPUCOMPARE_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace CPUCompare
|
||||
{
|
||||
// start the server
|
||||
void StartServer();
|
||||
|
||||
// connect as client
|
||||
void ConnectAsClient();
|
||||
|
||||
// stop
|
||||
void Stop();
|
||||
|
||||
// sync
|
||||
int Sync();
|
||||
|
||||
// IsEnabled
|
||||
bool IsEnabled();
|
||||
|
||||
// IsServer
|
||||
bool IsServer();
|
||||
|
||||
void SetBlockStart(u32 addr);
|
||||
}
|
||||
|
||||
#endif
|
466
Source/Core/Core/Src/HW/CommandProcessor.cpp
Normal file
466
Source/Core/Core/Src/HW/CommandProcessor.cpp
Normal file
@ -0,0 +1,466 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "../Plugins/Plugin_Video.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../CoreTiming.h"
|
||||
|
||||
#include "MathUtil.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include "Memmap.h"
|
||||
#include "PeripheralInterface.h"
|
||||
#include "GPFifo.h"
|
||||
#include "CPU.h"
|
||||
#include "../Core.h"
|
||||
#include "CommandProcessor.h"
|
||||
|
||||
namespace CommandProcessor
|
||||
{
|
||||
// look for 1002 verts, breakpoint there, see why next draw is flushed
|
||||
// TODO(ector): Warn on bbox read/write
|
||||
|
||||
// Fifo Status Register
|
||||
union UCPStatusReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned OverflowHiWatermark : 1;
|
||||
unsigned UnderflowLoWatermark : 1;
|
||||
unsigned ReadIdle : 1;
|
||||
unsigned CommandIdle : 1;
|
||||
unsigned Breakpoint : 1;
|
||||
unsigned : 11;
|
||||
};
|
||||
u16 Hex;
|
||||
UCPStatusReg() {Hex = 0; }
|
||||
UCPStatusReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
// Fifo Control Register
|
||||
union UCPCtrlReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned GPReadEnable : 1;
|
||||
unsigned CPIntEnable : 1;
|
||||
unsigned FifoOverflowIntEnable : 1;
|
||||
unsigned FifoUnderflowIntEnable : 1;
|
||||
unsigned GPLinkEnable : 1;
|
||||
unsigned BPEnable : 1;
|
||||
unsigned : 10;
|
||||
};
|
||||
u16 Hex;
|
||||
UCPCtrlReg() {Hex = 0; }
|
||||
UCPCtrlReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
// Fifo Control Register
|
||||
union UCPClearReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned ClearFifoOverflow : 1;
|
||||
unsigned ClearFifoUnderflow : 1;
|
||||
unsigned ClearMetrices : 1;
|
||||
unsigned : 13;
|
||||
};
|
||||
u16 Hex;
|
||||
UCPClearReg() {Hex = 0; }
|
||||
UCPClearReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
// variables
|
||||
UCPStatusReg m_CPStatusReg;
|
||||
UCPCtrlReg m_CPCtrlReg;
|
||||
UCPClearReg m_CPClearReg;
|
||||
|
||||
int m_bboxleft;
|
||||
int m_bboxtop;
|
||||
int m_bboxright;
|
||||
int m_bboxbottom;
|
||||
u16 m_tokenReg;
|
||||
|
||||
CPFifo fifo; //This one is shared between gfx thread and emulator thread
|
||||
|
||||
|
||||
// function
|
||||
void UpdateFifoRegister();
|
||||
void UpdateInterrupts();
|
||||
|
||||
inline void WriteLow (u32& _reg, u16 lowbits) {_reg = (_reg & 0xFFFF0000) | lowbits;}
|
||||
inline void WriteHigh(u32& _reg, u16 highbits) {_reg = (_reg & 0x0000FFFF) | ((u32)highbits << 16);}
|
||||
inline u16 ReadLow (u32 _reg) {return (u16)(_reg & 0xFFFF);}
|
||||
inline u16 ReadHigh (u32 _reg) {return (u16)(_reg >> 16);}
|
||||
|
||||
void Init()
|
||||
{
|
||||
m_CPStatusReg.Hex = 0;
|
||||
m_CPStatusReg.CommandIdle = 1;
|
||||
m_CPStatusReg.ReadIdle = 1;
|
||||
|
||||
m_CPCtrlReg.Hex = 0;
|
||||
|
||||
m_bboxleft = 0;
|
||||
m_bboxtop = 0;
|
||||
m_bboxright = 640;
|
||||
m_bboxbottom = 480;
|
||||
|
||||
m_tokenReg = 0;
|
||||
|
||||
fifo.bFF_GPReadEnable = false;
|
||||
fifo.bFF_GPLinkEnable = false;
|
||||
fifo.bFF_BPEnable = false;
|
||||
#ifdef _WIN32
|
||||
InitializeCriticalSection(&fifo.sync);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
|
||||
if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||
{
|
||||
if ((_Address&0xFFF)>=0x20)
|
||||
{
|
||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 &&
|
||||
!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
||||
;
|
||||
fifo.bPauseRead = true;
|
||||
}
|
||||
|
||||
}
|
||||
switch (_Address & 0xFFF)
|
||||
{
|
||||
case STATUS_REGISTER: _rReturnValue = m_CPStatusReg.Hex; return;
|
||||
case CTRL_REGISTER: _rReturnValue = m_CPCtrlReg.Hex; return;
|
||||
case CLEAR_REGISTER: _rReturnValue = m_CPClearReg.Hex; return;
|
||||
|
||||
case FIFO_TOKEN_REGISTER: _rReturnValue = m_tokenReg; return;
|
||||
case FIFO_BOUNDING_BOX_LEFT: _rReturnValue = m_bboxleft; return;
|
||||
case FIFO_BOUNDING_BOX_RIGHT: _rReturnValue = m_bboxright; return;
|
||||
case FIFO_BOUNDING_BOX_TOP: _rReturnValue = m_bboxtop; return;
|
||||
case FIFO_BOUNDING_BOX_BOTTOM: _rReturnValue = m_bboxbottom; return;
|
||||
|
||||
case FIFO_BASE_LO: _rReturnValue = ReadLow (fifo.CPBase); return;
|
||||
case FIFO_BASE_HI: _rReturnValue = ReadHigh(fifo.CPBase); return;
|
||||
case FIFO_END_LO: _rReturnValue = ReadLow (fifo.CPEnd); return;
|
||||
case FIFO_END_HI: _rReturnValue = ReadHigh(fifo.CPEnd); return;
|
||||
case FIFO_HI_WATERMARK_LO: _rReturnValue = ReadLow (fifo.CPHiWatermark); return;
|
||||
case FIFO_HI_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPHiWatermark); return;
|
||||
case FIFO_LO_WATERMARK_LO: _rReturnValue = ReadLow (fifo.CPLoWatermark); return;
|
||||
case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return;
|
||||
case FIFO_RW_DISTANCE_LO: _rReturnValue = ReadLow (fifo.CPReadWriteDistance); return;
|
||||
case FIFO_RW_DISTANCE_HI: _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); return;
|
||||
case FIFO_WRITE_POINTER_LO: _rReturnValue = ReadLow (fifo.CPWritePointer); return;
|
||||
case FIFO_WRITE_POINTER_HI: _rReturnValue = ReadHigh(fifo.CPWritePointer); return;
|
||||
case FIFO_READ_POINTER_LO: _rReturnValue = ReadLow (fifo.CPReadPointer); return;
|
||||
case FIFO_READ_POINTER_HI: _rReturnValue = ReadHigh(fifo.CPReadPointer); return;
|
||||
case FIFO_BP_LO: _rReturnValue = ReadLow (fifo.CPBreakpoint); return;
|
||||
case FIFO_BP_HI: _rReturnValue = ReadHigh(fifo.CPBreakpoint); return;
|
||||
|
||||
|
||||
// case 0x64:
|
||||
// return 4; //Number of clocks per vertex.. todo: calculate properly
|
||||
|
||||
//add all the other regs here? are they ever read?
|
||||
default:
|
||||
{
|
||||
// char szTemp[111];
|
||||
// sprintf(szTemp, "CCommandProcessor 0x%x", (_Address&0xFFF));
|
||||
// MessageBox(NULL, szTemp, "mm", MB_OK);
|
||||
}
|
||||
_rReturnValue = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
fifo.bPauseRead = false;
|
||||
}
|
||||
|
||||
bool AllowIdleSkipping()
|
||||
{
|
||||
return !Core::g_CoreStartupParameter.bUseDualCore || (!m_CPCtrlReg.CPIntEnable && !m_CPCtrlReg.BPEnable);
|
||||
}
|
||||
|
||||
void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
LOG(COMMANDPROCESSOR, "(w): 0x%04x @ 0x%08x",_Value,_Address);
|
||||
|
||||
//Spin until queue is empty - it WILL become empty because this is the only thread
|
||||
//that submits data
|
||||
|
||||
if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||
{
|
||||
|
||||
if ((_Address&0xFFF) >= 0x20)
|
||||
{
|
||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance > 0 &&
|
||||
!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
||||
;
|
||||
fifo.bPauseRead = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection(&fifo.sync);
|
||||
#endif
|
||||
switch (_Address & 0xFFF)
|
||||
{
|
||||
case STATUS_REGISTER:
|
||||
{
|
||||
UCPStatusReg tmpStatus(_Value);
|
||||
|
||||
// set the flags to "all is okay"
|
||||
m_CPStatusReg.OverflowHiWatermark = 0;
|
||||
m_CPStatusReg.UnderflowLoWatermark = 0;
|
||||
m_CPStatusReg.ReadIdle = 1;
|
||||
m_CPStatusReg.CommandIdle = 1;
|
||||
|
||||
// breakpoint
|
||||
if (tmpStatus.Breakpoint)
|
||||
{
|
||||
m_CPStatusReg.Breakpoint = 0;
|
||||
}
|
||||
fifo.bFF_Breakpoint = m_CPStatusReg.Breakpoint;
|
||||
|
||||
// update interrupts
|
||||
UpdateInterrupts();
|
||||
|
||||
LOG(COMMANDPROCESSOR,"write to STATUS_REGISTER : %04x", _Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CTRL_REGISTER:
|
||||
{
|
||||
m_CPCtrlReg.Hex = _Value;
|
||||
|
||||
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable ? true : false;
|
||||
fifo.bFF_GPLinkEnable = m_CPCtrlReg.GPLinkEnable ? true : false;
|
||||
fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable ? true : false;
|
||||
|
||||
UpdateInterrupts();
|
||||
|
||||
LOG(COMMANDPROCESSOR,"write to CTRL_REGISTER : %04x", _Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLEAR_REGISTER:
|
||||
{
|
||||
UCPClearReg tmpClearReg(_Value);
|
||||
m_CPClearReg.Hex = 0;
|
||||
|
||||
LOG(COMMANDPROCESSOR,"write to CLEAR_REGISTER : %04x",_Value);
|
||||
}
|
||||
break;
|
||||
|
||||
// Fifo Registers
|
||||
case FIFO_TOKEN_REGISTER: m_tokenReg = _Value; break;
|
||||
|
||||
case FIFO_BASE_LO: WriteLow ((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break;
|
||||
case FIFO_BASE_HI: WriteHigh((u32 &)fifo.CPBase, _Value); fifo.CPBase &= 0xFFFFFFE0; break;
|
||||
case FIFO_END_LO: WriteLow ((u32 &)fifo.CPEnd, _Value); fifo.CPEnd &= 0xFFFFFFE0; break;
|
||||
case FIFO_END_HI: WriteHigh((u32 &)fifo.CPEnd, _Value); fifo.CPEnd &= 0xFFFFFFE0; break;
|
||||
|
||||
// Hm. Should we really & these with FFFFFFE0?
|
||||
case FIFO_WRITE_POINTER_LO: WriteLow ((u32 &)fifo.CPWritePointer, _Value); fifo.CPWritePointer &= 0xFFFFFFE0; break;
|
||||
case FIFO_WRITE_POINTER_HI: WriteHigh((u32 &)fifo.CPWritePointer, _Value); fifo.CPWritePointer &= 0xFFFFFFE0; break;
|
||||
case FIFO_READ_POINTER_LO: WriteLow ((u32 &)fifo.CPReadPointer, _Value); fifo.CPReadPointer &= 0xFFFFFFE0; break;
|
||||
case FIFO_READ_POINTER_HI: WriteHigh((u32 &)fifo.CPReadPointer, _Value); fifo.CPReadPointer &= 0xFFFFFFE0; break;
|
||||
|
||||
case FIFO_HI_WATERMARK_LO: WriteLow ((u32 &)fifo.CPHiWatermark, _Value); break;
|
||||
case FIFO_HI_WATERMARK_HI: WriteHigh((u32 &)fifo.CPHiWatermark, _Value); break;
|
||||
case FIFO_LO_WATERMARK_LO: WriteLow ((u32 &)fifo.CPLoWatermark, _Value); break;
|
||||
case FIFO_LO_WATERMARK_HI: WriteHigh((u32 &)fifo.CPLoWatermark, _Value); break;
|
||||
|
||||
case FIFO_BP_LO: WriteLow ((u32 &)fifo.CPBreakpoint, _Value); break;
|
||||
case FIFO_BP_HI: WriteHigh((u32 &)fifo.CPBreakpoint, _Value); break;
|
||||
|
||||
// ignored writes
|
||||
case FIFO_RW_DISTANCE_HI:
|
||||
case FIFO_RW_DISTANCE_LO:
|
||||
break;
|
||||
}
|
||||
|
||||
// update the registers and run the fifo
|
||||
// This will recursively enter fifo.sync, TODO(ector): is this good?
|
||||
UpdateFifoRegister();
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection(&fifo.sync);
|
||||
#endif
|
||||
fifo.bPauseRead = false; // pauseread is not actually used anywhere! TOOD(ector): huh!
|
||||
}
|
||||
|
||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
_rReturnValue = 0;
|
||||
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Read32 from CommandProccessor at 0x%08x", _Address);
|
||||
}
|
||||
|
||||
void Write32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Write32 at CommandProccessor at 0x%08x", _Address);
|
||||
}
|
||||
|
||||
void GatherPipeBursted()
|
||||
{
|
||||
// we arn't linked, so we don't care about gather pipe data
|
||||
if (!fifo.bFF_GPLinkEnable)
|
||||
return;
|
||||
|
||||
if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||
{
|
||||
// update the fifo-pointer
|
||||
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
|
||||
if (fifo.CPWritePointer >= fifo.CPEnd)
|
||||
fifo.CPWritePointer = fifo.CPBase;
|
||||
|
||||
// Wait for GPU to catch up
|
||||
while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) &&
|
||||
fifo.CPReadWriteDistance > (s32)fifo.CPHiWatermark)
|
||||
Common::SleepCurrentThread(1);
|
||||
#ifdef _WIN32
|
||||
InterlockedExchangeAdd((LONG*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
||||
#endif
|
||||
|
||||
// check if we are in sync
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == CPeripheralInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync");
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPBase == CPeripheralInterface::Fifo_CPUBase, "FIFOs linked but out of sync");
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == CPeripheralInterface::Fifo_CPUEnd, "FIFOs linked but out of sync");
|
||||
|
||||
if (fifo.bFF_Breakpoint)
|
||||
{
|
||||
m_CPStatusReg.Breakpoint = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
|
||||
if (fifo.CPWritePointer >= fifo.CPEnd)
|
||||
fifo.CPWritePointer = fifo.CPBase;
|
||||
// check if we are in sync
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == CPeripheralInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync");
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPBase == CPeripheralInterface::Fifo_CPUBase, "FIFOs linked but out of sync");
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == CPeripheralInterface::Fifo_CPUEnd, "FIFOs linked but out of sync");
|
||||
|
||||
UpdateFifoRegister();
|
||||
}
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// UpdateFifoRegister
|
||||
// It's no problem if the gfx falls behind a little bit. Better make sure to stop the cpu thread
|
||||
// when the distance is way huge, though.
|
||||
// So:
|
||||
// CPU thread
|
||||
/// 0. Write data (done before entering this)
|
||||
// 1. Compute distance
|
||||
// 2. If distance > threshold, sleep and goto 1
|
||||
// GPU thread
|
||||
// 1. Compute distance
|
||||
// 2. If distance < threshold, sleep and goto 1 (or wait for trigger?)
|
||||
// 3. Read and use a bit of data, goto 1
|
||||
void UpdateFifoRegister()
|
||||
{
|
||||
// update the distance
|
||||
#ifdef _WIN32
|
||||
if (Core::g_CoreStartupParameter.bUseDualCore) EnterCriticalSection(&fifo.sync);
|
||||
#endif
|
||||
int wp = fifo.CPWritePointer;
|
||||
int rp = fifo.CPReadPointer;
|
||||
if (wp >= rp)
|
||||
fifo.CPReadWriteDistance = wp - rp;
|
||||
else
|
||||
fifo.CPReadWriteDistance = (wp - fifo.CPBase) +
|
||||
(fifo.CPEnd - rp);
|
||||
#ifdef _WIN32
|
||||
if (Core::g_CoreStartupParameter.bUseDualCore) LeaveCriticalSection(&fifo.sync);
|
||||
#endif
|
||||
if (!Core::g_CoreStartupParameter.bUseDualCore)
|
||||
{
|
||||
// check if we are able to run this buffer
|
||||
if ((fifo.bFF_GPReadEnable) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
||||
{
|
||||
while(fifo.CPReadWriteDistance > 0)
|
||||
{
|
||||
// check if we are on a breakpoint
|
||||
if (fifo.bFF_BPEnable)
|
||||
{
|
||||
//MessageBox(0,"Breakpoint enabled",0,0);
|
||||
if ((fifo.CPReadPointer & ~0x1F) == (fifo.CPBreakpoint & ~0x1F))
|
||||
{
|
||||
//_assert_msg_(GEKKO,0,"BP: %08x",fifo.CPBreakpoint);
|
||||
fifo.bFF_Breakpoint = 1;
|
||||
m_CPStatusReg.Breakpoint = 1;
|
||||
//g_VideoInitialize.pUpdateInterrupts();
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// read the data and send it to the VideoPlugin
|
||||
|
||||
u8 *ptr = Memory::GetPointer(fifo.CPReadPointer);
|
||||
fifo.CPReadPointer += 32;
|
||||
// We are going to do FP math on the main thread so have to save the current state
|
||||
SaveSSEState();
|
||||
LoadDefaultSSEState();
|
||||
PluginVideo::Video_SendFifoData(ptr);
|
||||
LoadSSEState();
|
||||
|
||||
fifo.CPReadWriteDistance -= 32;
|
||||
|
||||
// increase the ReadPtr
|
||||
if (fifo.CPReadPointer >= fifo.CPEnd)
|
||||
{
|
||||
fifo.CPReadPointer = fifo.CPBase;
|
||||
LOG(COMMANDPROCESSOR, "BUFFER LOOP");
|
||||
// MessageBox(NULL, "loop", "now", MB_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
if (fifo.bFF_BPEnable && fifo.bFF_Breakpoint)
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_CP, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_CP, false);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
|
||||
{
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
void UpdateInterruptsFromVideoPlugin()
|
||||
{
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, &UpdateInterrupts_Wrapper, "CP:UI");
|
||||
}
|
||||
|
||||
} // end of namespace CommandProcessor
|
99
Source/Core/Core/Src/HW/CommandProcessor.h
Normal file
99
Source/Core/Core/Src/HW/CommandProcessor.h
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _COMMANDPROCESSOR_H
|
||||
#define _COMMANDPROCESSOR_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
extern bool MT;
|
||||
namespace CommandProcessor
|
||||
{
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
STATUS_REGISTER = 0x00,
|
||||
CTRL_REGISTER = 0x02,
|
||||
CLEAR_REGISTER = 0x04,
|
||||
FIFO_TOKEN_REGISTER = 0x0E,
|
||||
FIFO_BOUNDING_BOX_LEFT = 0x10,
|
||||
FIFO_BOUNDING_BOX_RIGHT = 0x12,
|
||||
FIFO_BOUNDING_BOX_TOP = 0x14,
|
||||
FIFO_BOUNDING_BOX_BOTTOM = 0x16,
|
||||
FIFO_BASE_LO = 0x20,
|
||||
FIFO_BASE_HI = 0x22,
|
||||
FIFO_END_LO = 0x24,
|
||||
FIFO_END_HI = 0x26,
|
||||
FIFO_HI_WATERMARK_LO = 0x28,
|
||||
FIFO_HI_WATERMARK_HI = 0x2a,
|
||||
FIFO_LO_WATERMARK_LO = 0x2c,
|
||||
FIFO_LO_WATERMARK_HI = 0x2e,
|
||||
FIFO_RW_DISTANCE_LO = 0x30,
|
||||
FIFO_RW_DISTANCE_HI = 0x32,
|
||||
FIFO_WRITE_POINTER_LO = 0x34,
|
||||
FIFO_WRITE_POINTER_HI = 0x36,
|
||||
FIFO_READ_POINTER_LO = 0x38,
|
||||
FIFO_READ_POINTER_HI = 0x3A,
|
||||
FIFO_BP_LO = 0x3C,
|
||||
FIFO_BP_HI = 0x3E
|
||||
};
|
||||
struct CPFifo
|
||||
{
|
||||
// fifo registers
|
||||
volatile u32 CPBase;
|
||||
volatile u32 CPEnd;
|
||||
u32 CPHiWatermark;
|
||||
u32 CPLoWatermark;
|
||||
volatile s32 CPReadWriteDistance;
|
||||
volatile u32 CPWritePointer;
|
||||
volatile u32 CPReadPointer;
|
||||
volatile u32 CPBreakpoint;
|
||||
|
||||
volatile bool bFF_GPReadEnable;
|
||||
volatile bool bFF_BPEnable;
|
||||
volatile bool bFF_GPLinkEnable;
|
||||
volatile bool bFF_Breakpoint;
|
||||
volatile bool bPauseRead;
|
||||
#ifdef _WIN32
|
||||
CRITICAL_SECTION sync;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern CPFifo fifo;
|
||||
// Init
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Read
|
||||
void HWCALL Read16(u16& _rReturnValue, const u32 _Address);
|
||||
void HWCALL Write16(const u16 _Data, const u32 _Address);
|
||||
void HWCALL Read32(u32& _rReturnValue, const u32 _Address);
|
||||
void HWCALL Write32(const u32 _Data, const u32 _Address);
|
||||
|
||||
// for CGPFIFO
|
||||
void GatherPipeBursted();
|
||||
void UpdateInterrupts();
|
||||
void UpdateInterruptsFromVideoPlugin();
|
||||
|
||||
bool AllowIdleSkipping();
|
||||
|
||||
} // end of namespace CommandProcessor
|
||||
|
||||
#endif
|
||||
|
557
Source/Core/Core/Src/HW/DSP.cpp
Normal file
557
Source/Core/Core/Src/HW/DSP.cpp
Normal file
@ -0,0 +1,557 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "DSP.h"
|
||||
|
||||
#include "../CoreTiming.h"
|
||||
#include "../Core.h"
|
||||
#include "CPU.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Memmap.h"
|
||||
#include "PeripheralInterface.h"
|
||||
#include "AudioInterface.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../Plugins/Plugin_DSP.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
|
||||
// register offsets
|
||||
enum
|
||||
{
|
||||
DSP_MAIL_TO_DSP_HI = 0x5000,
|
||||
DSP_MAIL_TO_DSP_LO = 0x5002,
|
||||
DSP_MAIL_FROM_DSP_HI = 0x5004,
|
||||
DSP_MAIL_FROM_DSP_LO = 0x5006,
|
||||
DSP_CONTROL = 0x500A,
|
||||
DSP_INTERRUPT_CONTROL = 0x5010,
|
||||
AUDIO_DMA_START_HI = 0x5030,
|
||||
AUDIO_DMA_START_LO = 0x5032,
|
||||
AUDIO_DMA_CONTROL_LEN = 0x5036,
|
||||
AUDIO_DMA_BYTES_LEFT = 0x503A,
|
||||
AR_DMA_MMADDR_H = 0x5020,
|
||||
AR_DMA_MMADDR_L = 0x5022,
|
||||
AR_DMA_ARADDR_H = 0x5024,
|
||||
AR_DMA_ARADDR_L = 0x5026,
|
||||
AR_DMA_CNT_H = 0x5028,
|
||||
AR_DMA_CNT_L = 0x502A
|
||||
};
|
||||
|
||||
// aram size and mask
|
||||
enum
|
||||
{
|
||||
ARAM_SIZE = 0x01000000, // 16 MB
|
||||
ARAM_MASK = 0x00FFFFFF
|
||||
};
|
||||
|
||||
// UARAMCount
|
||||
union UARAMCount
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned count : 31;
|
||||
unsigned dir : 1;
|
||||
};
|
||||
};
|
||||
|
||||
// UDSPControl
|
||||
#define DSP_CONTROL_MASK 0x0C07
|
||||
union UDSPControl
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned DSPReset : 1; // Write 1 to reset and waits for 0
|
||||
unsigned DSPAssertInt : 1;
|
||||
unsigned DSPHalt : 1;
|
||||
|
||||
unsigned AI : 1;
|
||||
unsigned AI_mask : 1;
|
||||
unsigned ARAM : 1;
|
||||
unsigned ARAM_mask : 1;
|
||||
unsigned DSP : 1;
|
||||
unsigned DSP_mask : 1;
|
||||
|
||||
unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag
|
||||
unsigned unk3 : 1;
|
||||
unsigned DSPInit : 1; // DSPInit() writes to this flag (1 as long as dsp PC is in IROM?)
|
||||
unsigned pad : 4;
|
||||
};
|
||||
};
|
||||
|
||||
// DSPState
|
||||
struct DSPState
|
||||
{
|
||||
u32 IntControl;
|
||||
UDSPControl DSPControl;
|
||||
|
||||
DSPState()
|
||||
{
|
||||
IntControl = 0;
|
||||
DSPControl.Hex = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// UDSPControl
|
||||
union UAudioDMAControl
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned NumSamples : 15;
|
||||
unsigned Enabled : 1;
|
||||
};
|
||||
|
||||
UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex)
|
||||
{}
|
||||
};
|
||||
|
||||
// AudioDMA
|
||||
struct AudioDMA
|
||||
{
|
||||
u32 SourceAddress;
|
||||
UAudioDMAControl AudioDMAControl;
|
||||
u32 SamplesLeft;
|
||||
};
|
||||
|
||||
// ARDMA
|
||||
struct ARDMA
|
||||
{
|
||||
u32 MMAddr;
|
||||
u32 ARAddr;
|
||||
UARAMCount Cnt;
|
||||
bool CntValid[2];
|
||||
|
||||
ARDMA()
|
||||
{
|
||||
MMAddr = 0;
|
||||
ARAddr = 0;
|
||||
Cnt.Hex = 0;
|
||||
CntValid[0] = false;
|
||||
CntValid[1] = false;
|
||||
}
|
||||
};
|
||||
|
||||
u8 *g_ARAM = NULL;
|
||||
DSPState g_dspState;
|
||||
AudioDMA g_audioDMA;
|
||||
ARDMA g_arDMA;
|
||||
u16 g_AR_READY_FLAG = 0x01;
|
||||
u16 g_AR_MODE = 0x43; // 0x23 -> Zelda standard mode (standard ARAM access ??)
|
||||
// 0x43 -> written by OSAudioInit at the UCode upload (upload UCode)
|
||||
// 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ??
|
||||
|
||||
void UpdateInterrupts();
|
||||
void Update_ARAM_DMA();
|
||||
void WriteARAM(u8 _iValue, u32 _iAddress);
|
||||
bool Update_DSP_ReadRegister();
|
||||
void Update_DSP_WriteRegister();
|
||||
|
||||
void Init()
|
||||
{
|
||||
g_ARAM = (u8 *)AllocateMemoryPages(ARAM_SIZE);
|
||||
g_dspState.DSPControl.Hex = 0;
|
||||
g_dspState.DSPControl.DSPHalt = 1;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
FreeMemoryPages(g_ARAM, ARAM_SIZE);
|
||||
g_ARAM = NULL;
|
||||
}
|
||||
|
||||
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
// WTF is this check about? DSP is at 5000 TODO remove
|
||||
if ((_iAddress & 0x6C00) != 0x6c00)
|
||||
{
|
||||
if (_iAddress != 0xCC005004) {
|
||||
LOG(DSPINTERFACE, "DSPInterface(r16) 0x%08x", _iAddress);
|
||||
}
|
||||
|
||||
switch (_iAddress & 0xFFFF)
|
||||
{
|
||||
// ==================================================================================
|
||||
// AI_REGS 0x5000+
|
||||
// ==================================================================================
|
||||
case DSP_MAIL_TO_DSP_HI:
|
||||
_uReturnValue = PluginDSP::DSP_ReadMailboxHigh(true);
|
||||
return;
|
||||
|
||||
case DSP_MAIL_TO_DSP_LO:
|
||||
_uReturnValue = PluginDSP::DSP_ReadMailboxLow(true);
|
||||
return;
|
||||
|
||||
case DSP_MAIL_FROM_DSP_HI:
|
||||
_uReturnValue = PluginDSP::DSP_ReadMailboxHigh(false);
|
||||
return;
|
||||
|
||||
case DSP_MAIL_FROM_DSP_LO:
|
||||
_uReturnValue = PluginDSP::DSP_ReadMailboxLow(false);
|
||||
return;
|
||||
|
||||
case DSP_CONTROL:
|
||||
_uReturnValue = (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) |
|
||||
(PluginDSP::DSP_ReadControlRegister() & DSP_CONTROL_MASK);
|
||||
return;
|
||||
|
||||
// ==================================================================================
|
||||
// AR_REGS 0x501x+
|
||||
// ==================================================================================
|
||||
case 0x5012:
|
||||
_uReturnValue = g_AR_MODE;
|
||||
return;
|
||||
|
||||
case 0x5016: // ready flag ?
|
||||
_uReturnValue = g_AR_READY_FLAG;
|
||||
return;
|
||||
|
||||
case 0x501a:
|
||||
_uReturnValue = 0x000;
|
||||
return;
|
||||
|
||||
case AR_DMA_MMADDR_H: _uReturnValue = g_arDMA.MMAddr>>16; return;
|
||||
case AR_DMA_MMADDR_L: _uReturnValue = g_arDMA.MMAddr&0xFFFF; return;
|
||||
case AR_DMA_ARADDR_H: _uReturnValue = g_arDMA.ARAddr>>16; return;
|
||||
case AR_DMA_ARADDR_L: _uReturnValue = g_arDMA.ARAddr&0xFFFF; return;
|
||||
case AR_DMA_CNT_H: _uReturnValue = g_arDMA.Cnt.Hex>>16; return;
|
||||
case AR_DMA_CNT_L: _uReturnValue = g_arDMA.Cnt.Hex&0xFFFF; return;
|
||||
|
||||
// ==================================================================================
|
||||
// DMA_REGS 0x5030+
|
||||
// ==================================================================================
|
||||
case AUDIO_DMA_BYTES_LEFT:
|
||||
_uReturnValue = g_audioDMA.SamplesLeft;
|
||||
return;
|
||||
|
||||
case AUDIO_DMA_START_LO:
|
||||
_uReturnValue = g_audioDMA.SourceAddress & 0xFFFF;
|
||||
return;
|
||||
|
||||
case AUDIO_DMA_START_HI:
|
||||
_uReturnValue = g_audioDMA.SourceAddress>>16;
|
||||
return;
|
||||
|
||||
case AUDIO_DMA_CONTROL_LEN:
|
||||
_uReturnValue = g_audioDMA.AudioDMAControl.Hex;
|
||||
return;
|
||||
|
||||
default:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
}
|
||||
_uReturnValue = 0x000;
|
||||
}
|
||||
|
||||
void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
LOG(DSPINTERFACE, "DSPInterface(w16) 0x%04x 0x%08x", _Value, _Address);
|
||||
|
||||
switch(_Address & 0xFFFF)
|
||||
{
|
||||
// ==================================================================================
|
||||
// DSP Regs 0x5000+
|
||||
// ==================================================================================
|
||||
|
||||
case DSP_MAIL_TO_DSP_HI:
|
||||
PluginDSP::DSP_WriteMailboxHigh(true, _Value);
|
||||
break;
|
||||
|
||||
case DSP_MAIL_TO_DSP_LO:
|
||||
PluginDSP::DSP_WriteMailboxLow(true, _Value);
|
||||
break;
|
||||
|
||||
case DSP_MAIL_FROM_DSP_HI:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
|
||||
case DSP_MAIL_FROM_DSP_LO:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
|
||||
// ==================================================================================
|
||||
// Control Register
|
||||
// ==================================================================================
|
||||
case DSP_CONTROL:
|
||||
{
|
||||
UDSPControl tmpControl;
|
||||
tmpControl.Hex = (_Value& ~DSP_CONTROL_MASK) |
|
||||
(PluginDSP::DSP_WriteControlRegister(_Value) & DSP_CONTROL_MASK);
|
||||
|
||||
// Update DSP related flags
|
||||
g_dspState.DSPControl.DSPReset = tmpControl.DSPReset;
|
||||
g_dspState.DSPControl.DSPAssertInt = tmpControl.DSPAssertInt;
|
||||
g_dspState.DSPControl.DSPHalt = tmpControl.DSPHalt;
|
||||
g_dspState.DSPControl.DSPInit = tmpControl.DSPInit;
|
||||
|
||||
// Interrupt (mask)
|
||||
g_dspState.DSPControl.AI_mask = tmpControl.AI_mask;
|
||||
g_dspState.DSPControl.ARAM_mask = tmpControl.ARAM_mask;
|
||||
g_dspState.DSPControl.DSP_mask = tmpControl.DSP_mask;
|
||||
|
||||
// Interrupt
|
||||
if (tmpControl.AI) g_dspState.DSPControl.AI = 0;
|
||||
if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
|
||||
if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0;
|
||||
|
||||
// g_ARAM
|
||||
g_dspState.DSPControl.ARAM_DMAState = 0; // keep g_ARAM DMA State zero
|
||||
|
||||
// unknown
|
||||
g_dspState.DSPControl.unk3 = tmpControl.unk3;
|
||||
g_dspState.DSPControl.pad = tmpControl.pad;
|
||||
if (g_dspState.DSPControl.pad != 0)
|
||||
{
|
||||
LOG(DSPINTERFACE, "DSPInterface(w) g_dspState.DSPControl gets an unknown value");
|
||||
CCPU::Break();
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
|
||||
// ==================================================================================
|
||||
// AR_REGS 0x501x+
|
||||
// ==================================================================================
|
||||
|
||||
case 0x5012:
|
||||
g_AR_MODE = _Value;
|
||||
break;
|
||||
|
||||
case 0x5016:
|
||||
g_AR_READY_FLAG = 0x01; // write what ya want we set 0x01 (rdy flag ??)
|
||||
break;
|
||||
|
||||
case 0x501a:
|
||||
break;
|
||||
|
||||
case AR_DMA_MMADDR_H:
|
||||
g_arDMA.MMAddr = (g_arDMA.MMAddr & 0xFFFF) | (_Value<<16); break;
|
||||
case AR_DMA_MMADDR_L:
|
||||
g_arDMA.MMAddr = (g_arDMA.MMAddr & 0xFFFF0000) | (_Value); break;
|
||||
|
||||
case AR_DMA_ARADDR_H:
|
||||
g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF) | (_Value<<16); break;
|
||||
case AR_DMA_ARADDR_L:
|
||||
g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF0000) | (_Value); break;
|
||||
|
||||
case AR_DMA_CNT_H:
|
||||
g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF) | (_Value<<16);
|
||||
g_arDMA.CntValid[0] = true;
|
||||
Update_ARAM_DMA();
|
||||
break;
|
||||
|
||||
case AR_DMA_CNT_L:
|
||||
g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (_Value);
|
||||
g_arDMA.CntValid[1] = true;
|
||||
Update_ARAM_DMA();
|
||||
break;
|
||||
|
||||
// ==================================================================================
|
||||
// Audio DMA_REGS 0x5030+
|
||||
// ==================================================================================
|
||||
case AUDIO_DMA_START_HI:
|
||||
g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF) | (_Value<<16);
|
||||
break;
|
||||
|
||||
case AUDIO_DMA_START_LO:
|
||||
g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF0000) | (_Value);
|
||||
break;
|
||||
|
||||
case AUDIO_DMA_CONTROL_LEN: // called by AIStartDMA()
|
||||
g_audioDMA.AudioDMAControl.Hex = _Value;
|
||||
g_audioDMA.SamplesLeft = g_audioDMA.AudioDMAControl.NumSamples;
|
||||
|
||||
if (g_audioDMA.AudioDMAControl.Enabled)
|
||||
{
|
||||
PluginDSP::DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumSamples);
|
||||
g_audioDMA.SamplesLeft = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_DMA_BYTES_LEFT:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
|
||||
default:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
LOG(DSPINTERFACE, "DSPInterface(r) 0x%08x", _iAddress);
|
||||
switch (_iAddress & 0xFFFF)
|
||||
{
|
||||
case DSP_INTERRUPT_CONTROL:
|
||||
_uReturnValue = g_dspState.IntControl;
|
||||
return;
|
||||
|
||||
default:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
}
|
||||
_uReturnValue = 0;
|
||||
}
|
||||
|
||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
{
|
||||
LOG(DSPINTERFACE, "DSPInterface(w) 0x%08x 0x%08x", _iValue, _iAddress);
|
||||
|
||||
switch (_iAddress & 0xFFFF)
|
||||
{
|
||||
// ==================================================================================
|
||||
// AR_REGS - i dont know why they are accessed 32 bit too ...
|
||||
// ==================================================================================
|
||||
|
||||
case AR_DMA_MMADDR_H:
|
||||
g_arDMA.MMAddr = _iValue;
|
||||
break;
|
||||
|
||||
case AR_DMA_ARADDR_H:
|
||||
g_arDMA.ARAddr = _iValue;
|
||||
break;
|
||||
|
||||
case AR_DMA_CNT_H:
|
||||
g_arDMA.Cnt.Hex = _iValue;
|
||||
g_arDMA.CntValid[0] = g_arDMA.CntValid[1] = true;
|
||||
Update_ARAM_DMA();
|
||||
break;
|
||||
|
||||
default:
|
||||
_dbg_assert_(DSPINTERFACE,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// UpdateInterrupts
|
||||
//
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
if ((g_dspState.DSPControl.AI & g_dspState.DSPControl.AI_mask) ||
|
||||
(g_dspState.DSPControl.ARAM & g_dspState.DSPControl.ARAM_mask) ||
|
||||
(g_dspState.DSPControl.DSP & g_dspState.DSPControl.DSP_mask))
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DSP, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DSP, false);
|
||||
}
|
||||
}
|
||||
|
||||
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_AI: g_dspState.DSPControl.AI = _bSet ? 1 : 0; break;
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
void GenerateDSPInterrupt_Wrapper(u64 userdata, int cyclesLate)
|
||||
{
|
||||
GenerateDSPInterrupt((DSPInterruptType)(userdata&0xFFFF), (bool)((userdata>>16) & 1));
|
||||
}
|
||||
|
||||
// CALLED FROM DSP PLUGIN, POSSIBLY THREADED
|
||||
void GenerateDSPInterruptFromPlugin(DSPInterruptType type, bool _bSet)
|
||||
{
|
||||
CoreTiming::ScheduleEvent_Threadsafe(
|
||||
0, GenerateDSPInterrupt_Wrapper, "DSPInt", type | (_bSet<<16));
|
||||
}
|
||||
|
||||
void Update_ARAM_DMA()
|
||||
{
|
||||
// check if the count reg is valid
|
||||
if (!g_arDMA.CntValid[0] || !g_arDMA.CntValid[1])
|
||||
return;
|
||||
g_arDMA.CntValid[0] = g_arDMA.CntValid[1] = false;
|
||||
|
||||
LOG(DSPINTERFACE,"ARAM DMA triggered");
|
||||
|
||||
//TODO: speedup
|
||||
if (g_arDMA.Cnt.dir)
|
||||
{
|
||||
//read from ARAM
|
||||
LOG(DSPINTERFACE,"ARAM DMA read %08x bytes from %08x to Mem: %08x",g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr);
|
||||
u32 iMemAddress = g_arDMA.MMAddr;
|
||||
u32 iARAMAddress = g_arDMA.ARAddr;
|
||||
|
||||
// TODO(??): sanity check instead of writing bogus data?
|
||||
for (u32 i=0; i<g_arDMA.Cnt.count; i++)
|
||||
{
|
||||
u32 tmp = (iARAMAddress < ARAM_SIZE) ? g_ARAM[iARAMAddress] : 0x05050505;
|
||||
Memory::Write_U8(tmp, iMemAddress);
|
||||
|
||||
iMemAddress++;
|
||||
iARAMAddress++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 iMemAddress = g_arDMA.MMAddr;
|
||||
u32 iARAMAddress = g_arDMA.ARAddr;
|
||||
|
||||
//write to g_ARAM
|
||||
LOG(DSPINTERFACE,"g_ARAM DMA write %08x bytes from %08x to Aram: %08x",g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr);
|
||||
for (u32 i=0; i<g_arDMA.Cnt.count; i++)
|
||||
{
|
||||
if (iARAMAddress < ARAM_SIZE)
|
||||
g_ARAM[iARAMAddress] = Memory::Read_U8(iMemAddress);
|
||||
|
||||
iMemAddress++;
|
||||
iARAMAddress++;
|
||||
}
|
||||
}
|
||||
|
||||
g_arDMA.Cnt.count = 0;
|
||||
GenerateDSPInterrupt(INT_ARAM);
|
||||
}
|
||||
|
||||
u8 ReadARAM(const u32 _iAddress)
|
||||
{
|
||||
// _dbg_assert_(DSPINTERFACE,(_iAddress) < ARAM_SIZE);
|
||||
return g_ARAM[_iAddress & ARAM_MASK];
|
||||
}
|
||||
|
||||
u8* GetARAMPtr()
|
||||
{
|
||||
return g_ARAM;
|
||||
}
|
||||
|
||||
void WriteARAM(u8 _iValue, u32 _iAddress)
|
||||
{
|
||||
// _dbg_assert_(DSPINTERFACE,(_iAddress) < ARAM_SIZE);
|
||||
//rouge leader writes WAY outside
|
||||
//not really surprising since it uses a totally different memory model :P
|
||||
g_ARAM[_iAddress & ARAM_MASK] = _iValue;
|
||||
}
|
||||
|
||||
} // end of namespace DSP
|
||||
|
58
Source/Core/Core/Src/HW/DSP.h
Normal file
58
Source/Core/Core/Src/HW/DSP.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _DSPINTERFACE_H
|
||||
#define _DSPINTERFACE_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
|
||||
enum DSPInterruptType
|
||||
{
|
||||
INT_DSP = 0,
|
||||
INT_ARAM = 1,
|
||||
INT_AI = 2
|
||||
};
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void GenerateDSPInterrupt(DSPInterruptType _DSPInterruptType, bool _bSet = true);
|
||||
void GenerateDSPInterruptFromPlugin(DSPInterruptType _DSPInterruptType, bool _bSet = true);
|
||||
|
||||
// Read32
|
||||
void HWCALL Read16(u16& _uReturnValue, const u32 _uAddress);
|
||||
void HWCALL Read32(u32& _uReturnValue, const u32 _uAddress);
|
||||
|
||||
// Write
|
||||
void HWCALL Write16(const u16 _uValue, const u32 _uAddress);
|
||||
void HWCALL Write32(const u32 _uValue, const u32 _uAddress);
|
||||
|
||||
// Audio/DSP Plugin Helper
|
||||
u8 ReadARAM(const u32 _uAddress);
|
||||
|
||||
// Debugger Helper
|
||||
u8* GetARAMPtr();
|
||||
|
||||
|
||||
void UpdateAudioDMA();
|
||||
|
||||
}// end of namespace DSP
|
||||
|
||||
#endif
|
||||
|
574
Source/Core/Core/Src/HW/DVDInterface.cpp
Normal file
574
Source/Core/Core/Src/HW/DVDInterface.cpp
Normal file
@ -0,0 +1,574 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "StreamADPCM.H"
|
||||
#include "DVDInterface.h"
|
||||
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "PeripheralInterface.h"
|
||||
#include "Memmap.h"
|
||||
|
||||
#include "../VolumeHandler.h"
|
||||
|
||||
namespace DVDInterface
|
||||
{
|
||||
|
||||
/*
|
||||
20975: 00000000 DVD (zzz_80146b84 ??, 0x80146bf8) : DVD(r): 0xcc006004
|
||||
20976: 00000000 DVD (zzz_80146b84 ??, 0x80146c00) : DVD(w): 0x00000000 @ 0xcc006004
|
||||
20977: 00000000 DVD (DVDLowRead, 0x801448a8) : DVD(w): 0x00000020 @ 0xcc006018
|
||||
20978: 00000000 DVD (Read, 0x80144744) : DVD(w): 0xa8000000 @ 0xcc006008
|
||||
20979: 00000000 DVD (Read, 0x80144750) : DVD(w): 0x01094227 @ 0xcc00600c
|
||||
20980: 00000000 DVD (Read, 0x80144758) : DVD(w): 0x00000020 @ 0xcc006010
|
||||
20981: 00000000 DVD (Read, 0x8014475c) : DVD(w): 0x8167cc80 @ 0xcc006014
|
||||
20982: 00000000 DVD (Read, 0x80144760) : DVD(w): 0x00000020 @ 0xcc006018
|
||||
20983: 00000000 DVD (Read, 0x80144768) : DVD(w): 0x00000003 @ 0xcc00601c
|
||||
20984: 00000000 DVD: DVD: Read ISO: DVDOffset=0425089c, DMABuffer=0167cc80, SrcLength=00000020, DMALength=00000020
|
||||
20989: 00000000 DVD (zzz_801442fc ??, 0x80144388) : DVD(r): 0xcc006000
|
||||
20990: 00000000 DVD (zzz_801442fc ??, 0x801443d8) : DVD(w): 0x0000003a @ 0xcc006000
|
||||
20992: 00000000 DVD (zzz_801442fc ??, 0x801444d0) : DVD(w): 0x00000000 @ 0xcc006004
|
||||
20993: 00000000 DVD (zzz_80146e44 ??, 0x80146fcc) : DVD(r): 0xcc006018
|
||||
|
||||
After this, Cubivore infinitely calls DVDGetDriveStatus, which does not even
|
||||
bother to check any DVD regs
|
||||
*/
|
||||
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
DI_STATUS_REGISTER = 0x00,
|
||||
DI_COVER_REGISTER = 0x04,
|
||||
DI_COMMAND_0 = 0x08,
|
||||
DI_COMMAND_1 = 0x0C,
|
||||
DI_COMMAND_2 = 0x10,
|
||||
DI_DMA_ADDRESS_REGISTER = 0x14,
|
||||
DI_DMA_LENGTH_REGISTER = 0x18,
|
||||
DI_DMA_CONTROL_REGISTER = 0x1C,
|
||||
DI_IMMEDIATE_DATA_BUFFER = 0x20,
|
||||
DI_CONFIG_REGISTER = 0x24
|
||||
};
|
||||
|
||||
|
||||
// DVD IntteruptTypes
|
||||
enum DVDInterruptType
|
||||
{
|
||||
INT_DEINT = 0,
|
||||
INT_TCINT = 1,
|
||||
INT_BRKINT = 2,
|
||||
INT_CVRINT
|
||||
};
|
||||
|
||||
// DI Status Register
|
||||
union UDISR
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned BREAK : 1; // Stop the Device + Interrupt
|
||||
unsigned DEINITMASK : 1; // Access Device Error Int Mask
|
||||
unsigned DEINT : 1; // Access Device Error Int
|
||||
unsigned TCINTMASK : 1; // Transfer Complete Int Mask
|
||||
unsigned TCINT : 1; // Transfer Complete Int
|
||||
unsigned BRKINTMASK : 1;
|
||||
unsigned BRKINT : 1; // w 1: clear brkint
|
||||
unsigned : 25;
|
||||
};
|
||||
UDISR() {Hex = 0;}
|
||||
UDISR(u32 _hex) {Hex = _hex;}
|
||||
};
|
||||
|
||||
// DI Cover Register
|
||||
union UDICVR
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned CVR : 1; // 0: Cover closed 1: Cover open
|
||||
unsigned CVRINTMASK : 1; // 1: Interrupt enabled;
|
||||
unsigned CVRINT : 1; // 1: Interrupt clear
|
||||
unsigned : 29;
|
||||
};
|
||||
UDICVR() {Hex = 0;}
|
||||
UDICVR(u32 _hex) {Hex = _hex;}
|
||||
};
|
||||
|
||||
// DI DMA Address Register
|
||||
union UDIDMAAddressRegister
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned Address : 26;
|
||||
unsigned : 6;
|
||||
};
|
||||
};
|
||||
|
||||
// DI DMA Address Length Register
|
||||
union UDIDMAAddressLength
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned Length : 26;
|
||||
unsigned : 6;
|
||||
};
|
||||
};
|
||||
|
||||
// DI DMA Control Register
|
||||
union UDIDMAControlRegister
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned TSTART : 1; // w:1 start r:0 ready
|
||||
unsigned DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command)
|
||||
unsigned RW : 1; // 0: Read Command (DVD to Memory) 1: Write COmmand (Memory to DVD)
|
||||
unsigned : 29;
|
||||
};
|
||||
};
|
||||
|
||||
// DI Config Register
|
||||
union UDIConfigRegister
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned CONFIG : 8;
|
||||
unsigned : 24;
|
||||
};
|
||||
UDIConfigRegister() {Hex = 0;}
|
||||
UDIConfigRegister(u32 _hex) {Hex = _hex;}
|
||||
};
|
||||
|
||||
// hardware registers
|
||||
struct DVDMemStruct
|
||||
{
|
||||
UDISR StatusReg;
|
||||
UDICVR CoverReg;
|
||||
u32 Command[3];
|
||||
UDIDMAAddressRegister DMAAddress;
|
||||
UDIDMAAddressLength DMALength;
|
||||
UDIDMAControlRegister DMAControlReg;
|
||||
u32 Immediate;
|
||||
UDIConfigRegister ConfigReg;
|
||||
u32 AudioStart;
|
||||
u32 AudioPos;
|
||||
u32 AudioLength;
|
||||
};
|
||||
|
||||
DVDMemStruct dvdMem;
|
||||
|
||||
// helper
|
||||
u32 g_ErrorCode = 0x00;
|
||||
bool g_bDiscInside = true;
|
||||
|
||||
void UpdateInterrupts();
|
||||
void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt);
|
||||
void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg);
|
||||
|
||||
void Init()
|
||||
{
|
||||
dvdMem.StatusReg.Hex = 0;
|
||||
dvdMem.CoverReg.Hex = 0;
|
||||
dvdMem.Command[0] = 0;
|
||||
dvdMem.Command[1] = 0;
|
||||
dvdMem.Command[2] = 0;
|
||||
dvdMem.DMAAddress.Hex = 0;
|
||||
dvdMem.DMALength.Hex = 0;
|
||||
dvdMem.DMAControlReg.Hex = 0;
|
||||
dvdMem.Immediate = 0;
|
||||
dvdMem.ConfigReg.Hex = 0;
|
||||
dvdMem.AudioStart = 0;
|
||||
dvdMem.AudioPos = 0;
|
||||
dvdMem.AudioLength = 0;
|
||||
|
||||
// SetLidOpen(true);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetDiscInside(bool _DiscInside)
|
||||
{
|
||||
g_bDiscInside = _DiscInside;
|
||||
}
|
||||
|
||||
void SetLidOpen(bool _bOpen)
|
||||
{
|
||||
if (_bOpen)
|
||||
dvdMem.CoverReg.CVR = 1;
|
||||
else
|
||||
dvdMem.CoverReg.CVR = 0;
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
bool IsLidOpen()
|
||||
{
|
||||
if (dvdMem.CoverReg.CVR)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength)
|
||||
{
|
||||
return VolumeHandler::ReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength);
|
||||
}
|
||||
|
||||
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples)
|
||||
{
|
||||
if (dvdMem.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;
|
||||
VolumeHandler::ReadToPtr(_pDestBuffer, dvdMem.AudioPos, _iNumSamples);
|
||||
|
||||
//
|
||||
// FIX THIS
|
||||
//
|
||||
// loop check
|
||||
//
|
||||
dvdMem.AudioPos += _iNumSamples;
|
||||
if (dvdMem.AudioPos >= dvdMem.AudioStart + dvdMem.AudioLength)
|
||||
{
|
||||
dvdMem.AudioPos = dvdMem.AudioStart;
|
||||
NGCADPCM::InitFilter();
|
||||
}
|
||||
|
||||
//LOG(DVDINTERFACE,"ReadADPCM");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
LOG(DVDINTERFACE, "DVD(r): 0x%08x", _iAddress);
|
||||
|
||||
switch (_iAddress & 0xFFF)
|
||||
{
|
||||
case DI_STATUS_REGISTER: _uReturnValue = dvdMem.StatusReg.Hex; return;
|
||||
case DI_COVER_REGISTER: _uReturnValue = dvdMem.CoverReg.Hex; return;
|
||||
case DI_COMMAND_0: _uReturnValue = dvdMem.Command[0]; return;
|
||||
case DI_COMMAND_1: _uReturnValue = dvdMem.Command[1]; return;
|
||||
case DI_COMMAND_2: _uReturnValue = dvdMem.Command[2]; return;
|
||||
case DI_DMA_ADDRESS_REGISTER: _uReturnValue = dvdMem.DMAAddress.Hex; return;
|
||||
case DI_DMA_LENGTH_REGISTER: _uReturnValue = dvdMem.DMALength.Hex; return;
|
||||
case DI_DMA_CONTROL_REGISTER: _uReturnValue = dvdMem.DMAControlReg.Hex; return;
|
||||
case DI_IMMEDIATE_DATA_BUFFER: _uReturnValue = dvdMem.Immediate; return;
|
||||
case DI_CONFIG_REGISTER:
|
||||
{
|
||||
dvdMem.ConfigReg.Hex = 0x000000FF;
|
||||
_uReturnValue = dvdMem.ConfigReg.Hex;
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
_dbg_assert_(DVDINTERFACE,0);
|
||||
}
|
||||
|
||||
_uReturnValue = 0;
|
||||
}
|
||||
|
||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
{
|
||||
LOG(DVDINTERFACE, "DVD(w): 0x%08x @ 0x%08x", _iValue, _iAddress);
|
||||
|
||||
switch (_iAddress & 0x3FF)
|
||||
{
|
||||
case DI_STATUS_REGISTER:
|
||||
{
|
||||
UDISR tmpStatusReg(_iValue);
|
||||
|
||||
dvdMem.StatusReg.DEINITMASK = tmpStatusReg.DEINITMASK;
|
||||
dvdMem.StatusReg.TCINTMASK = tmpStatusReg.TCINTMASK;
|
||||
dvdMem.StatusReg.BRKINTMASK = tmpStatusReg.BRKINTMASK;
|
||||
|
||||
if (tmpStatusReg.DEINT) dvdMem.StatusReg.DEINT = 0;
|
||||
if (tmpStatusReg.TCINT) dvdMem.StatusReg.TCINT = 0;
|
||||
if (tmpStatusReg.BRKINT) dvdMem.StatusReg.BRKINT = 0;
|
||||
|
||||
if (tmpStatusReg.BREAK)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, 0);
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
|
||||
case DI_COVER_REGISTER:
|
||||
{
|
||||
UDICVR tmpCoverReg(_iValue);
|
||||
|
||||
dvdMem.CoverReg.CVR = 0;
|
||||
dvdMem.CoverReg.CVRINTMASK = tmpCoverReg.CVRINTMASK;
|
||||
if (tmpCoverReg.CVRINT) dvdMem.CoverReg.CVRINT = 0;
|
||||
|
||||
UpdateInterrupts();
|
||||
|
||||
_dbg_assert_(DVDINTERFACE, (tmpCoverReg.CVR == 0));
|
||||
}
|
||||
break;
|
||||
|
||||
case DI_COMMAND_0: dvdMem.Command[0] = _iValue; break;
|
||||
case DI_COMMAND_1: dvdMem.Command[1] = _iValue; break;
|
||||
case DI_COMMAND_2: dvdMem.Command[2] = _iValue; break;
|
||||
|
||||
case DI_DMA_ADDRESS_REGISTER:
|
||||
{
|
||||
dvdMem.DMAAddress.Hex = _iValue;
|
||||
_dbg_assert_(DVDINTERFACE, ((dvdMem.DMAAddress.Hex & 0x1F) == 0));
|
||||
}
|
||||
break;
|
||||
case DI_DMA_LENGTH_REGISTER: dvdMem.DMALength.Hex = _iValue; break;
|
||||
case DI_DMA_CONTROL_REGISTER:
|
||||
{
|
||||
dvdMem.DMAControlReg.Hex = _iValue;
|
||||
if (dvdMem.DMAControlReg.TSTART)
|
||||
{
|
||||
ExecuteCommand(dvdMem.DMAControlReg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DI_IMMEDIATE_DATA_BUFFER: dvdMem.Immediate = _iValue; break;
|
||||
case DI_CONFIG_REGISTER:
|
||||
{
|
||||
UDIConfigRegister tmpConfigReg(_iValue);
|
||||
|
||||
dvdMem.ConfigReg.CONFIG = tmpConfigReg.CONFIG;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_dbg_assert_msg_(DVDINTERFACE, 0, "Write to unknown DI address 0x%08x", _iAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
if ((dvdMem.StatusReg.DEINT & dvdMem.StatusReg.DEINITMASK) ||
|
||||
(dvdMem.StatusReg.TCINT & dvdMem.StatusReg.TCINTMASK) ||
|
||||
(dvdMem.StatusReg.BRKINT & dvdMem.StatusReg.BRKINTMASK) ||
|
||||
(dvdMem.CoverReg.CVRINT & dvdMem.CoverReg.CVRINTMASK))
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DI, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_DI, false);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt)
|
||||
{
|
||||
switch(_DVDInterrupt)
|
||||
{
|
||||
case INT_DEINT: dvdMem.StatusReg.DEINT = 1; break;
|
||||
case INT_TCINT: dvdMem.StatusReg.TCINT = 1; break;
|
||||
case INT_BRKINT: dvdMem.StatusReg.BRKINT = 1; break;
|
||||
case INT_CVRINT: dvdMem.CoverReg.CVRINT = 1; break;
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
bool m_bStream = false;
|
||||
|
||||
void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg)
|
||||
{
|
||||
_dbg_assert_(DVDINTERFACE, _DMAControlReg.RW == 0); // only DVD to Memory
|
||||
|
||||
switch ((dvdMem.Command[0] & 0xFF000000) >> 24)
|
||||
{
|
||||
//=========================================================================================================
|
||||
// DRIVE INFO (DMA)
|
||||
// Command/Subcommand/Padding <- 12000000
|
||||
// Command0 <- 0
|
||||
// Command1 <- 0x20
|
||||
// Command2 <- Address in ram of the buffer
|
||||
//
|
||||
// output buffer:
|
||||
// 0000-0001 revisionLevel
|
||||
// 0002-0003 deviceCode
|
||||
// 0004-0007 releaseDate
|
||||
// 0008-001F padding(0)
|
||||
//=========================================================================================================
|
||||
case 0x12:
|
||||
{
|
||||
u32 offset = dvdMem.Command[1];
|
||||
// u32 sourcelength = dvdMem.Command[2];
|
||||
u32 destbuffer = dvdMem.DMAAddress.Address;
|
||||
u32 destlength = dvdMem.DMALength.Length;
|
||||
dvdMem.DMALength.Length = 0;
|
||||
|
||||
LOG(DVDINTERFACE, "[WARNING] DVD: Get drive info offset=%08x, destbuffer=%08x, destlength=%08x", offset * 4, destbuffer, destlength);
|
||||
|
||||
// metroid uses this...
|
||||
for (unsigned int i = 0; i < destlength / 4; i++)
|
||||
{
|
||||
Memory::Write_U32(0, destbuffer + i * 4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// READ (DMA)
|
||||
// Command/Subcommand/Padding <- A8000000
|
||||
// Command0 <- Position on DVD shr 2
|
||||
// Command1 <- Length of the read
|
||||
// Command2 <- Address in ram of the buffer
|
||||
//=========================================================================================================
|
||||
case 0xA8:
|
||||
{
|
||||
if (g_bDiscInside)
|
||||
{
|
||||
u32 iDVDOffset = dvdMem.Command[1] << 2;
|
||||
u32 iSrcLength = dvdMem.Command[2];
|
||||
LOG(DVDINTERFACE, "DVD: Read ISO: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x",iDVDOffset,dvdMem.DMAAddress.Address,iSrcLength,dvdMem.DMALength.Length);
|
||||
_dbg_assert_(DVDINTERFACE, iSrcLength == dvdMem.DMALength.Length);
|
||||
|
||||
if (VolumeHandler::ReadToPtr(Memory::GetPointer(dvdMem.DMAAddress.Address), iDVDOffset, dvdMem.DMALength.Length) != true)
|
||||
{
|
||||
PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is no disc to read
|
||||
GenerateDVDInterrupt(INT_DEINT);
|
||||
g_ErrorCode = 0x03023A00;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// SEEK (Immediate)
|
||||
// Command/Subcommand/Padding <- AB000000
|
||||
// Command0 <- Position on DVD shr 2
|
||||
//=========================================================================================================
|
||||
case 0xAB:
|
||||
{
|
||||
u32 offset = dvdMem.Command[1] << 2;
|
||||
LOG(DVDINTERFACE, "DVD: Trying to seek: offset=%08x", offset);
|
||||
}
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// REQUEST ERROR (Immediate)
|
||||
// Command/Subcommand/Padding <- E0000000
|
||||
//=========================================================================================================
|
||||
case 0xE0:
|
||||
LOG(DVDINTERFACE, "DVD: Requesting error");
|
||||
dvdMem.Immediate = g_ErrorCode;
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// AUDIOSTREAM (Immediate)
|
||||
// Command/Subcommand/Padding <- E1??0000 ?? = subcommand
|
||||
// Command0 <- Position on DVD shr 2
|
||||
// Command1 <- Length of the stream
|
||||
//=========================================================================================================
|
||||
case 0xE1:
|
||||
{
|
||||
// i dunno if we need this check
|
||||
// if (m_bStream)
|
||||
// MessageBox(NULL, "dont overwrite a stream while you play it", "FATAL ERROR", MB_OK);
|
||||
|
||||
// subcommand
|
||||
|
||||
// ugly hack to catch the disable command
|
||||
if (dvdMem.Command[1]!=0)
|
||||
{
|
||||
u8 subCommand = (dvdMem.Command[0] & 0x00FF0000) >> 16;
|
||||
|
||||
dvdMem.AudioPos = dvdMem.Command[1] << 2;
|
||||
dvdMem.AudioStart = dvdMem.AudioPos;
|
||||
dvdMem.AudioLength = dvdMem.Command[2];
|
||||
NGCADPCM::InitFilter();
|
||||
|
||||
m_bStream = true;
|
||||
|
||||
LOG(DVDINTERFACE, "DVD(Audio) Stream subcmd = %02x offset = %08x length=%08x", subCommand, dvdMem.AudioPos, dvdMem.AudioLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// REQUEST AUDIO STATUS (Immediate)
|
||||
// Command/Subcommand/Padding <- E2000000
|
||||
//=========================================================================================================
|
||||
case 0xE2:
|
||||
{
|
||||
/* if (m_bStream)
|
||||
dvdMem.Immediate = 1;
|
||||
else
|
||||
dvdMem.Immediate = 0;*/
|
||||
}
|
||||
LOG(DVDINTERFACE, "DVD(Audio): Request Audio status");
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// STOP MOTOR (Immediate)
|
||||
// Command/Subcommand/Padding <- E3000000
|
||||
//=========================================================================================================
|
||||
case 0xE3:
|
||||
LOG(DVDINTERFACE, "DVD: Stop motor");
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// DVD AUDIO DISABLE (Immediate)`
|
||||
// Command/Subcommand/Padding <- E4000000 (disable)
|
||||
// Command/Subcommand/Padding <- E4010000 (enable)
|
||||
//=========================================================================================================
|
||||
case 0xE4:
|
||||
/* if (((dvdMem.Command[0] & 0x00FF0000) >> 16) == 1)
|
||||
{
|
||||
m_bStream = true;
|
||||
LOG(DVDINTERFACE, "DVD(Audio): Audio enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bStream = false;
|
||||
LOG(DVDINTERFACE, "DVD(Audio): Audio disabled");
|
||||
}*/
|
||||
break;
|
||||
|
||||
//=========================================================================================================
|
||||
// UNKNOWN DVD COMMAND
|
||||
//=========================================================================================================
|
||||
default:
|
||||
PanicAlert("DVD - Unknown DVD command %08x - fatal error", dvdMem.Command[0]);
|
||||
_dbg_assert_(DVDINTERFACE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
// transfer is done
|
||||
_DMAControlReg.TSTART = 0;
|
||||
dvdMem.DMALength.Length = 0;
|
||||
GenerateDVDInterrupt(INT_TCINT);
|
||||
g_ErrorCode = 0x00;
|
||||
}
|
||||
|
||||
} // namespace
|
49
Source/Core/Core/Src/HW/DVDInterface.h
Normal file
49
Source/Core/Core/Src/HW/DVDInterface.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _DVDINTERFACE_H
|
||||
#define _DVDINTERFACE_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace DVDInterface
|
||||
{
|
||||
|
||||
// Init
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void SetDiscInside(bool _DiscInside);
|
||||
|
||||
// Lid Functions
|
||||
void SetLidOpen(bool open);
|
||||
bool IsLidOpen();
|
||||
|
||||
// DVD Access Functions
|
||||
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength);
|
||||
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples);
|
||||
|
||||
// Read32
|
||||
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||
|
||||
// Write32
|
||||
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
|
||||
|
||||
} // end of namespace DVDInterface
|
||||
|
||||
#endif
|
||||
|
104
Source/Core/Core/Src/HW/EXI.cpp
Normal file
104
Source/Core/Core/Src/HW/EXI.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "PeripheralInterface.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_Channel.h"
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
NUM_CHANNELS = 3
|
||||
};
|
||||
|
||||
CEXIChannel *g_Channels;
|
||||
|
||||
void Init()
|
||||
{
|
||||
g_Channels = new CEXIChannel[3];
|
||||
g_Channels[0].m_ChannelId = 0;
|
||||
g_Channels[1].m_ChannelId = 1;
|
||||
g_Channels[2].m_ChannelId = 2;
|
||||
|
||||
g_Channels[0].AddDevice(EXIDEVICE_MEMORYCARD_A, 0);
|
||||
g_Channels[0].AddDevice(EXIDEVICE_IPL, 1);
|
||||
g_Channels[1].AddDevice(EXIDEVICE_MEMORYCARD_B, 0);
|
||||
g_Channels[2].AddDevice(EXIDEVICE_AD16, 0);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
delete [] g_Channels;
|
||||
g_Channels = 0;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
g_Channels[0].Update();
|
||||
g_Channels[1].Update();
|
||||
g_Channels[2].Update();
|
||||
}
|
||||
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
unsigned int iAddr = _iAddress & 0x3FF;
|
||||
unsigned int iRegister = (iAddr >> 2) % 5;
|
||||
unsigned int iChannel = (iAddr >> 2) / 5;
|
||||
|
||||
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
|
||||
|
||||
if (iChannel < NUM_CHANNELS)
|
||||
{
|
||||
g_Channels[iChannel].Read32(_uReturnValue, iRegister);
|
||||
}
|
||||
else
|
||||
{
|
||||
_uReturnValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
{
|
||||
int iAddr = _iAddress & 0x3FF;
|
||||
int iRegister = (iAddr >> 2) % 5;
|
||||
int iChannel = (iAddr >> 2) / 5;
|
||||
|
||||
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS)
|
||||
|
||||
if (iChannel < NUM_CHANNELS)
|
||||
g_Channels[iChannel].Write32(_iValue, iRegister);
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
for(int i=0; i<NUM_CHANNELS; i++)
|
||||
{
|
||||
if(g_Channels[i].isCausingInterrupt())
|
||||
{
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_EXI, false);
|
||||
}
|
||||
|
||||
} // end of namespace ExpansionInterface
|
43
Source/Core/Core/Src/HW/EXI.h
Normal file
43
Source/Core/Core/Src/HW/EXI.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _EXIINTERFACE_H
|
||||
#define _EXIINTERFACE_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
|
||||
// init
|
||||
void Init();
|
||||
|
||||
// shutdown
|
||||
void Shutdown();
|
||||
|
||||
// update
|
||||
void Update();
|
||||
|
||||
// updateInterrupts
|
||||
void UpdateInterrupts();
|
||||
|
||||
void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||
void HWCALL Write32(const u32 _iValue, const u32 _iAddress);
|
||||
|
||||
} // end of namespace ExpansionInterface
|
||||
|
||||
#endif
|
||||
|
278
Source/Core/Core/Src/HW/EXI_Channel.cpp
Normal file
278
Source/Core/Core/Src/HW/EXI_Channel.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "EXI_Channel.h"
|
||||
#include "EXI.h"
|
||||
|
||||
#include "PeripheralInterface.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
CEXIChannel::CEXIChannel() :
|
||||
m_DMAMemoryAddress(0),
|
||||
m_DMALength(0),
|
||||
m_ImmData(0),
|
||||
m_ChannelId(-1)
|
||||
{
|
||||
m_Control.hex = 0;
|
||||
m_Status.hex = 0;
|
||||
|
||||
m_Status.CHIP_SELECT = 1;
|
||||
|
||||
for (int i=0; i<NUM_DEVICES; i++)
|
||||
{
|
||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_DUMMY);
|
||||
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[i] != NULL);
|
||||
}
|
||||
|
||||
m_Status.TCINTMASK = 1;
|
||||
}
|
||||
|
||||
CEXIChannel::~CEXIChannel()
|
||||
{
|
||||
RemoveDevices();
|
||||
}
|
||||
|
||||
void CEXIChannel::RemoveDevices()
|
||||
{
|
||||
for (int i=0; i<NUM_DEVICES; i++)
|
||||
{
|
||||
if (m_pDevices[i] != NULL)
|
||||
{
|
||||
delete m_pDevices[i];
|
||||
m_pDevices[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot)
|
||||
{
|
||||
_dbg_assert_(EXPANSIONINTERFACE, _iSlot < NUM_DEVICES);
|
||||
|
||||
// delete the old device
|
||||
if (m_pDevices[_iSlot] != NULL)
|
||||
{
|
||||
delete m_pDevices[_iSlot];
|
||||
m_pDevices[_iSlot] = NULL;
|
||||
}
|
||||
|
||||
// create the new one
|
||||
m_pDevices[_iSlot] = EXIDevice_Create(_device);
|
||||
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[_iSlot] != NULL);
|
||||
}
|
||||
|
||||
void CEXIChannel::UpdateInterrupts()
|
||||
{
|
||||
ExpansionInterface::UpdateInterrupts();
|
||||
}
|
||||
|
||||
bool CEXIChannel::isCausingInterrupt()
|
||||
{
|
||||
if (m_ChannelId != 2) /* Channels 0 and 1: Memcard slot (device 0) produces interrupt */
|
||||
{
|
||||
if(m_pDevices[0]->IsInterruptSet())
|
||||
m_Status.EXIINT = 1;
|
||||
} else /* Channel 2: In fact, Channel 0, Device 2 (Serial A) produces interrupt */
|
||||
{
|
||||
if (this[-2].m_pDevices[2]->IsInterruptSet())
|
||||
m_Status.EXIINT = 1;
|
||||
}
|
||||
|
||||
if ((m_Status.EXIINT & m_Status.EXIINTMASK) ||
|
||||
(m_Status.TCINT & m_Status.TCINTMASK) ||
|
||||
(m_Status.EXTINT & m_Status.EXTINTMASK))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IEXIDevice* CEXIChannel::GetDevice(u8 _CHIP_SELECT)
|
||||
{
|
||||
switch(_CHIP_SELECT)
|
||||
{
|
||||
case 1: return m_pDevices[0];
|
||||
case 2: return m_pDevices[1];
|
||||
case 4: return m_pDevices[2];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CEXIChannel::Update()
|
||||
{
|
||||
// start the transfer
|
||||
for(int i=0; i<NUM_DEVICES; i++)
|
||||
{
|
||||
m_pDevices[i]->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "ExtensionInterface(R): channel: %i reg: %i", m_ChannelId, _iRegister);
|
||||
|
||||
switch (_iRegister)
|
||||
{
|
||||
case EXI_STATUS:
|
||||
{
|
||||
// check if a device is present
|
||||
for(int i=0; i<NUM_DEVICES; i++)
|
||||
{
|
||||
if(m_pDevices[i]->IsPresent())
|
||||
{
|
||||
m_Status.EXT = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_uReturnValue = m_Status.hex;
|
||||
return;
|
||||
}
|
||||
|
||||
case EXI_DMAADDR:
|
||||
_uReturnValue = m_DMAMemoryAddress;
|
||||
return;
|
||||
|
||||
case EXI_DMALENGTH:
|
||||
_uReturnValue = m_DMALength;
|
||||
return;
|
||||
|
||||
case EXI_DMACONTROL:
|
||||
_uReturnValue = m_Control.hex;
|
||||
return;
|
||||
|
||||
case EXI_IMMDATA:
|
||||
_uReturnValue = m_ImmData;
|
||||
return;
|
||||
}
|
||||
_dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||
_uReturnValue = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "ExtensionInterface(W): 0x%08x channel: %i reg: %i", _iValue, m_ChannelId, _iRegister);
|
||||
|
||||
switch (_iRegister)
|
||||
{
|
||||
case EXI_STATUS:
|
||||
{
|
||||
UEXI_STATUS newStatus(_iValue);
|
||||
|
||||
// static
|
||||
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
|
||||
m_Status.TCINTMASK = newStatus.TCINTMASK;
|
||||
m_Status.EXTINTMASK = newStatus.EXTINTMASK;
|
||||
m_Status.CLK = newStatus.CLK;
|
||||
m_Status.ROMDIS = newStatus.ROMDIS;
|
||||
|
||||
// Device
|
||||
if (m_Status.CHIP_SELECT != newStatus.CHIP_SELECT)
|
||||
{
|
||||
for (int i=0; i<NUM_DEVICES; i++)
|
||||
{
|
||||
u8 dwDeviceMask = 1 << i;
|
||||
IEXIDevice* pDevice = GetDevice(dwDeviceMask);
|
||||
if (pDevice != NULL)
|
||||
{
|
||||
if (((newStatus.CHIP_SELECT & dwDeviceMask) == dwDeviceMask) &&
|
||||
((m_Status.CHIP_SELECT & dwDeviceMask) == 0))
|
||||
// device gets activated
|
||||
pDevice->SetCS(1);
|
||||
|
||||
if (((newStatus.CHIP_SELECT & dwDeviceMask) == 0) &&
|
||||
((m_Status.CHIP_SELECT & dwDeviceMask) == dwDeviceMask))
|
||||
// device gets deactivated
|
||||
pDevice->SetCS(0);
|
||||
}
|
||||
}
|
||||
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
|
||||
}
|
||||
|
||||
// External Status
|
||||
IEXIDevice* pDevice = GetDevice(newStatus.CHIP_SELECT);
|
||||
if (pDevice != NULL)
|
||||
m_Status.EXT = pDevice->IsPresent() ? 1 : 0;
|
||||
else
|
||||
m_Status.EXT = 0;
|
||||
|
||||
// interrupt
|
||||
if (newStatus.EXIINT) m_Status.EXIINT = 0;
|
||||
if (newStatus.TCINT) m_Status.TCINT = 0;
|
||||
if (newStatus.EXTINT) m_Status.EXTINT = 0;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
|
||||
case EXI_DMAADDR:
|
||||
LOG(EXPANSIONINTERFACE, "EXI: Wrote DMABuf, chan %i", m_ChannelId);
|
||||
m_DMAMemoryAddress = _iValue;
|
||||
break;
|
||||
|
||||
case EXI_DMALENGTH:
|
||||
LOG(EXPANSIONINTERFACE, "EXI: Wrote DMASize, chan %i", m_ChannelId);
|
||||
m_DMALength = _iValue;
|
||||
break;
|
||||
|
||||
case EXI_DMACONTROL:
|
||||
LOG(EXPANSIONINTERFACE, "EXI: Wrote DMAControl, chan %i", m_ChannelId);
|
||||
m_Control.hex = _iValue;
|
||||
|
||||
if (m_Control.TSTART)
|
||||
{
|
||||
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT);
|
||||
if (pDevice == NULL)
|
||||
return;
|
||||
|
||||
if (m_Control.DMA == 0)
|
||||
{
|
||||
// immediate data
|
||||
switch (m_Control.RW)
|
||||
{
|
||||
case 0: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break;
|
||||
case 1: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break;
|
||||
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW);
|
||||
}
|
||||
m_Control.TSTART = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// DMA
|
||||
switch (m_Control.RW)
|
||||
{
|
||||
case 0: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break;
|
||||
case 1: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break;
|
||||
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW);
|
||||
}
|
||||
m_Control.TSTART = 0;
|
||||
}
|
||||
|
||||
if(!m_Control.TSTART) // completed !
|
||||
{
|
||||
m_Status.TCINT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EXI_IMMDATA:
|
||||
LOG(EXPANSIONINTERFACE, "EXI: Wrote IMMData, chan %i", m_ChannelId);
|
||||
m_ImmData = _iValue;
|
||||
break;
|
||||
}
|
||||
}
|
124
Source/Core/Core/Src/HW/EXI_Channel.h
Normal file
124
Source/Core/Core/Src/HW/EXI_Channel.h
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _EXICHANNEL_H
|
||||
#define _EXICHANNEL_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
|
||||
class CEXIChannel
|
||||
{
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
EXI_STATUS = 0,
|
||||
EXI_DMAADDR = 1,
|
||||
EXI_DMALENGTH = 2,
|
||||
EXI_DMACONTROL = 3,
|
||||
EXI_IMMDATA = 4
|
||||
};
|
||||
|
||||
// EXI Status Register
|
||||
union UEXI_STATUS
|
||||
{
|
||||
u32 hex;
|
||||
struct
|
||||
{
|
||||
unsigned EXIINTMASK : 1; // 31
|
||||
unsigned EXIINT : 1; //30
|
||||
unsigned TCINTMASK : 1; //29
|
||||
unsigned TCINT : 1; //28
|
||||
unsigned CLK : 3; //27
|
||||
unsigned CHIP_SELECT : 3; //24
|
||||
unsigned EXTINTMASK : 1; //21
|
||||
unsigned EXTINT : 1; //20
|
||||
unsigned EXT : 1; // External Insertion Status (1: External EXI device present) //19
|
||||
unsigned ROMDIS : 1; // ROM Disable //18
|
||||
unsigned :18;
|
||||
};
|
||||
UEXI_STATUS() {hex = 0;}
|
||||
UEXI_STATUS(u32 _hex) {hex = _hex;}
|
||||
};
|
||||
|
||||
// EXI Control Register
|
||||
union UEXI_CONTROL
|
||||
{
|
||||
u32 hex;
|
||||
struct
|
||||
{
|
||||
unsigned TSTART : 1;
|
||||
unsigned DMA : 1;
|
||||
unsigned RW : 2;
|
||||
unsigned TLEN : 2;
|
||||
unsigned :26;
|
||||
};
|
||||
};
|
||||
|
||||
UEXI_STATUS m_Status;
|
||||
UEXI_CONTROL m_Control;
|
||||
u32 m_DMAMemoryAddress;
|
||||
u32 m_DMALength;
|
||||
u32 m_ImmData;
|
||||
|
||||
// get device
|
||||
IEXIDevice* GetDevice(u8 _CHIP_SELECT);
|
||||
|
||||
// Devices
|
||||
enum
|
||||
{
|
||||
NUM_DEVICES = 3
|
||||
};
|
||||
|
||||
IEXIDevice* m_pDevices[NUM_DEVICES];
|
||||
|
||||
public:
|
||||
|
||||
// channeId for debugging
|
||||
u32 m_ChannelId;
|
||||
|
||||
// constructor
|
||||
CEXIChannel();
|
||||
|
||||
// destructor
|
||||
~CEXIChannel();
|
||||
|
||||
// Add a Device
|
||||
void AddDevice(const TEXIDevices _device, const unsigned int _iSlot);
|
||||
|
||||
// Remove all devices
|
||||
void RemoveDevices();
|
||||
|
||||
// update
|
||||
void Update();
|
||||
|
||||
// Read32
|
||||
void Read32(u32& _uReturnValue, const u32 _iRegister);
|
||||
|
||||
// isCausingInterrupt
|
||||
bool isCausingInterrupt();
|
||||
|
||||
// Write32
|
||||
void Write32(const u32 _iValue, const u32 _iRegister);
|
||||
|
||||
// update interrupts
|
||||
void UpdateInterrupts();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
149
Source/Core/Core/Src/HW/EXI_Device.cpp
Normal file
149
Source/Core/Core/Src/HW/EXI_Device.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Memmap.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceIPL.h"
|
||||
#include "EXI_DeviceMemoryCard.h"
|
||||
#include "EXI_DeviceAD16.h"
|
||||
|
||||
#include "../Core.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --- interface IEXIDevice ---
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
|
||||
{
|
||||
while (_uSize--)
|
||||
{
|
||||
u8 uByte = _uData >> 24;
|
||||
TransferByte(uByte);
|
||||
_uData <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
u32 IEXIDevice::ImmRead(u32 _uSize)
|
||||
{
|
||||
u32 uResult = 0;
|
||||
u32 uPosition = 0;
|
||||
while (_uSize--)
|
||||
{
|
||||
u8 uByte = 0;
|
||||
TransferByte(uByte);
|
||||
uResult |= uByte << (24-(uPosition++ * 8));
|
||||
}
|
||||
return uResult;
|
||||
}
|
||||
|
||||
void IEXIDevice::DMAWrite(u32 _uAddr, u32 _uSize)
|
||||
{
|
||||
// _dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||
while (_uSize--)
|
||||
{
|
||||
u8 uByte = Memory::Read_U8(_uAddr++);
|
||||
TransferByte(uByte);
|
||||
}
|
||||
}
|
||||
|
||||
void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize)
|
||||
{
|
||||
// _dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||
while (_uSize--)
|
||||
{
|
||||
u8 uByte = 0;
|
||||
TransferByte(uByte);
|
||||
Memory::Write_U8(uByte, _uAddr++);
|
||||
}
|
||||
};
|
||||
|
||||
bool IEXIDevice::IsPresent()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IEXIDevice::Update()
|
||||
{
|
||||
}
|
||||
|
||||
bool IEXIDevice::IsInterruptSet()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IEXIDevice::SetCS(int _iCS)
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --- class CEXIDummy ---
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// just a dummy that logs reads and writes
|
||||
// to be used for EXI devices we haven't emulated
|
||||
class CEXIDummy : public IEXIDevice
|
||||
{
|
||||
std::string m_strName;
|
||||
|
||||
void TransferByte(u8& _byte) {}
|
||||
|
||||
public:
|
||||
CEXIDummy(const std::string& _strName) :
|
||||
m_strName(_strName)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CEXIDummy(){}
|
||||
|
||||
void ImmWrite(u32 data, u32 size){LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x",m_strName.c_str(),data);}
|
||||
u32 ImmRead (u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead",m_strName.c_str()); return 0;}
|
||||
void DMAWrite(u32 addr, u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device",m_strName.c_str(),size,addr);}
|
||||
void DMARead (u32 addr, u32 size) {LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x",m_strName.c_str(),size,addr);}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// F A C T O R Y ////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
||||
{
|
||||
switch(_EXIDevice)
|
||||
{
|
||||
case EXIDEVICE_DUMMY:
|
||||
return new CEXIDummy("Dummy");
|
||||
break;
|
||||
|
||||
case EXIDEVICE_MEMORYCARD_A:
|
||||
return new CEXIMemoryCard("MemoryCardA", Core::GetStartupParameter().m_strMemoryCardA);
|
||||
break;
|
||||
|
||||
case EXIDEVICE_MEMORYCARD_B:
|
||||
return new CEXIMemoryCard("MemoryCardB", Core::GetStartupParameter().m_strMemoryCardB);
|
||||
break;
|
||||
|
||||
case EXIDEVICE_IPL:
|
||||
return new CEXIIPL();
|
||||
break;
|
||||
|
||||
case EXIDEVICE_AD16:
|
||||
return new CEXIAD16();
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
62
Source/Core/Core/Src/HW/EXI_Device.h
Normal file
62
Source/Core/Core/Src/HW/EXI_Device.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _EXIDEVICE_H
|
||||
#define _EXIDEVICE_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class IEXIDevice
|
||||
{
|
||||
private:
|
||||
// transfer function for this function
|
||||
virtual void TransferByte(u8& _byte) {};
|
||||
|
||||
public:
|
||||
// immdeiate copy functions
|
||||
virtual void ImmWrite(u32 _uData, u32 _uSize);
|
||||
virtual u32 ImmRead(u32 _uSize);
|
||||
|
||||
// dma copy functions
|
||||
virtual void DMAWrite(u32 _uAddr, u32 _uSize);
|
||||
virtual void DMARead (u32 _uAddr, u32 _uSize);
|
||||
|
||||
// is the Device insert ??
|
||||
virtual bool IsPresent();
|
||||
virtual void SetCS(int _iCS);
|
||||
|
||||
// update
|
||||
virtual void Update();
|
||||
|
||||
// is generating interrupt ?
|
||||
virtual bool IsInterruptSet();
|
||||
|
||||
virtual ~IEXIDevice() {};
|
||||
};
|
||||
|
||||
enum TEXIDevices
|
||||
{
|
||||
EXIDEVICE_DUMMY,
|
||||
EXIDEVICE_MEMORYCARD_A,
|
||||
EXIDEVICE_MEMORYCARD_B,
|
||||
EXIDEVICE_IPL,
|
||||
EXIDEVICE_AD16,
|
||||
};
|
||||
|
||||
extern IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice);
|
||||
|
||||
#endif
|
||||
|
92
Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp
Normal file
92
Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "../Core.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceAD16.h"
|
||||
|
||||
CEXIAD16::CEXIAD16() :
|
||||
m_uPosition(0),
|
||||
m_uCommand(0)
|
||||
{
|
||||
m_uAD16Register.U32 = 0x00;
|
||||
}
|
||||
|
||||
void CEXIAD16::SetCS(int cs)
|
||||
{
|
||||
if (cs)
|
||||
m_uPosition = 0;
|
||||
}
|
||||
|
||||
bool CEXIAD16::IsPresent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEXIAD16::TransferByte(u8& _byte)
|
||||
{
|
||||
if (m_uPosition == 0)
|
||||
{
|
||||
m_uCommand = _byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(m_uCommand)
|
||||
{
|
||||
case init:
|
||||
{
|
||||
m_uAD16Register.U32 = 0x04120000;
|
||||
switch(m_uPosition)
|
||||
{
|
||||
case 1: _dbg_assert_(EXPANSIONINTERFACE, (_byte == 0x00)); break; // just skip
|
||||
case 2: _byte = m_uAD16Register.U8[0]; break;
|
||||
case 3: _byte = m_uAD16Register.U8[1]; break;
|
||||
case 4: _byte = m_uAD16Register.U8[2]; break;
|
||||
case 5: _byte = m_uAD16Register.U8[3]; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case write:
|
||||
{
|
||||
switch(m_uPosition)
|
||||
{
|
||||
case 1: m_uAD16Register.U8[0] = _byte; break;
|
||||
case 2: m_uAD16Register.U8[1] = _byte; break;
|
||||
case 3: m_uAD16Register.U8[2] = _byte; break;
|
||||
case 4: m_uAD16Register.U8[3] = _byte; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case read:
|
||||
{
|
||||
switch(m_uPosition)
|
||||
{
|
||||
case 1: _byte = m_uAD16Register.U8[0]; break;
|
||||
case 2: _byte = m_uAD16Register.U8[1]; break;
|
||||
case 3: _byte = m_uAD16Register.U8[2]; break;
|
||||
case 4: _byte = m_uAD16Register.U8[3]; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_uPosition++;
|
||||
}
|
52
Source/Core/Core/Src/HW/EXI_DeviceAD16.h
Normal file
52
Source/Core/Core/Src/HW/EXI_DeviceAD16.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _EXIDEVICE_AD16_H
|
||||
#define _EXIDEVICE_AD16_H
|
||||
|
||||
class CEXIAD16 : public IEXIDevice
|
||||
{
|
||||
public:
|
||||
CEXIAD16();
|
||||
//! SetCS
|
||||
virtual void SetCS(int _iCS);
|
||||
//! Is device present?
|
||||
virtual bool IsPresent();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
init = 0x00,
|
||||
write = 0xa0,
|
||||
read = 0xa2
|
||||
};
|
||||
|
||||
union UAD16Reg
|
||||
{
|
||||
u32 U32;
|
||||
u32 U8[4];
|
||||
};
|
||||
|
||||
u32 m_uPosition;
|
||||
u32 m_uCommand;
|
||||
UAD16Reg m_uAD16Register;
|
||||
|
||||
virtual void TransferByte(u8& _uByte);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
276
Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp
Normal file
276
Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Timer.H"
|
||||
|
||||
#include "EXI_DeviceIPL.h"
|
||||
#include "../Core.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
// english
|
||||
const unsigned char sram_dump[64] = {
|
||||
0x04, 0x6B, 0xFB, 0x91, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x40,
|
||||
0x05, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xD2, 0x2B, 0x29, 0xD5, 0xC7, 0xAA, 0x12, 0xCB,
|
||||
0x21, 0x27, 0xD1, 0x53, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x86, 0x00, 0xFF, 0x4A, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// german
|
||||
const unsigned char sram_dump_german[64] ={
|
||||
0x1F, 0x66, 0xE0, 0x96, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0xEA, 0x19, 0x40,
|
||||
0x00, 0x00, 0x01, 0x3C, 0x12, 0xD5, 0xEA, 0xD3,
|
||||
0x00, 0xFA, 0x2D, 0x33, 0x13, 0x41, 0x26, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x84, 0xFF, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const char iplver[0x100] = "(C) 1999-2001 Nintendo. All rights reserved."
|
||||
"(C) 1999 ArtX Inc. All rights reserved."
|
||||
"PAL Revision 1.0 ";
|
||||
|
||||
CEXIIPL::CEXIIPL() :
|
||||
m_uPosition(0),
|
||||
m_uAddress(0),
|
||||
m_uRWOffset(0),
|
||||
m_count(0)
|
||||
{
|
||||
// load the IPL
|
||||
m_pIPL = (u8*)AllocateMemoryPages(ROM_SIZE);
|
||||
FILE* pStream = NULL;
|
||||
pStream = fopen("./Data/font_ansi.bin", "rb");
|
||||
if (pStream != NULL)
|
||||
{
|
||||
fseek(pStream, 0, SEEK_END);
|
||||
size_t filesize = ftell(pStream);
|
||||
rewind(pStream);
|
||||
|
||||
fread(m_pIPL + 0x001fcf00, 1, filesize, pStream);
|
||||
fclose(pStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Error: failed to load font_ansi.bin. Fonts may bug");
|
||||
}
|
||||
|
||||
pStream = fopen("./Data/font_sjis.bin", "rb");
|
||||
if (pStream != NULL)
|
||||
{
|
||||
fseek(pStream, 0, SEEK_END);
|
||||
size_t filesize = ftell(pStream);
|
||||
rewind(pStream);
|
||||
|
||||
fread(m_pIPL + 0x001aff00, 1, filesize, pStream);
|
||||
fclose(pStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Error: failed to load font_sjis.bin. Fonts may bug");
|
||||
}
|
||||
|
||||
memcpy(m_pIPL, iplver, sizeof(iplver));
|
||||
|
||||
// clear RTC
|
||||
memset(m_RTC, 0, sizeof(m_RTC));
|
||||
|
||||
// SRam
|
||||
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "rb");
|
||||
if (pStream != NULL)
|
||||
{
|
||||
fread(m_SRAM, 1, 64, pStream);
|
||||
fclose(pStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(m_SRAM, sram_dump, sizeof(m_SRAM));
|
||||
}
|
||||
|
||||
WriteProtectMemory(m_pIPL, ROM_SIZE);
|
||||
m_uAddress = 0;
|
||||
}
|
||||
|
||||
CEXIIPL::~CEXIIPL()
|
||||
{
|
||||
if (m_count > 0)
|
||||
{
|
||||
m_szBuffer[m_count] = 0x00;
|
||||
//MessageBox(NULL, m_szBuffer, "last message", MB_OK);
|
||||
}
|
||||
|
||||
if (m_pIPL != NULL)
|
||||
{
|
||||
FreeMemoryPages(m_pIPL, ROM_SIZE);
|
||||
m_pIPL = NULL;
|
||||
}
|
||||
|
||||
// SRam
|
||||
FILE* pStream = NULL;
|
||||
pStream = fopen(Core::GetStartupParameter().m_strSRAM.c_str(), "wb");
|
||||
if (pStream != NULL)
|
||||
{
|
||||
fwrite(m_SRAM, 1, 64, pStream);
|
||||
fclose(pStream);
|
||||
}
|
||||
}
|
||||
|
||||
void CEXIIPL::SetCS(int _iCS)
|
||||
{
|
||||
if (_iCS)
|
||||
{ // cs transition to high
|
||||
m_uPosition = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CEXIIPL::IsPresent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEXIIPL::TransferByte(u8& _uByte)
|
||||
{
|
||||
// the first 4 bytes must be the address
|
||||
// if we havnt read it, do it now
|
||||
if (m_uPosition < 4)
|
||||
{
|
||||
m_uAddress <<= 8;
|
||||
m_uAddress |= _uByte;
|
||||
m_uRWOffset = 0;
|
||||
_uByte = 0xFF;
|
||||
|
||||
// check if the command is complete
|
||||
if (m_uPosition == 3)
|
||||
{
|
||||
// get the time ...
|
||||
u32 GCTime = CEXIIPL::GetGCTime();
|
||||
u8* pGCTime = (u8*)&GCTime;
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
m_RTC[i] = pGCTime[i^3];
|
||||
}
|
||||
|
||||
#ifdef LOGGING
|
||||
|
||||
if ((m_uAddress & 0xF0000000) == 0xb0000000)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something");
|
||||
}
|
||||
else if ((m_uAddress & 0xF0000000) == 0x30000000)
|
||||
{
|
||||
// wii stuff perhaps wii SRAM?
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something (perhaps SRAM?)");
|
||||
}
|
||||
// debug only
|
||||
else if ((m_uAddress & 0x60000000) == 0)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: IPL access");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC access");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000100)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: SRAM access");
|
||||
}
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
||||
{
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART");
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg_assert_(EXPANSIONINTERFACE, 0);
|
||||
LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: illegal address %08x", m_uAddress);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// --- ROM ---
|
||||
//
|
||||
if ((m_uAddress & 0x60000000) == 0)
|
||||
{
|
||||
if ((m_uAddress & 0x80000000) == 0)
|
||||
_uByte = m_pIPL[((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset];
|
||||
}
|
||||
//
|
||||
// --- Real Time Clock (RTC) ---
|
||||
//
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20000000)
|
||||
{
|
||||
if (m_uAddress & 0x80000000)
|
||||
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)
|
||||
m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte;
|
||||
else
|
||||
_uByte = m_SRAM[(m_uAddress & 0x3F) + m_uRWOffset];
|
||||
}
|
||||
//
|
||||
// --- UART ---
|
||||
//
|
||||
else if ((m_uAddress & 0x7FFFFF00) == 0x20010000)
|
||||
{
|
||||
if (m_uAddress & 0x80000000)
|
||||
{
|
||||
m_szBuffer[m_count++] = _uByte;
|
||||
if ((m_count >= 256) || (_uByte == 0xD))
|
||||
{
|
||||
m_szBuffer[m_count] = 0x00;
|
||||
LOG(OSREPORT, "%s", m_szBuffer);
|
||||
memset(m_szBuffer, 0, sizeof(m_szBuffer));
|
||||
m_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
_uByte = 0x01; // dunno
|
||||
}
|
||||
m_uRWOffset++;
|
||||
}
|
||||
m_uPosition++;
|
||||
}
|
||||
|
||||
u32 CEXIIPL::GetGCTime()
|
||||
{
|
||||
// get sram bias
|
||||
u32 Bias;
|
||||
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
((u8*)&Bias)[i] = sram_dump[0xc + (i^3)];
|
||||
}
|
||||
|
||||
// get the time ...
|
||||
const u32 cJanuary2000 = 0x386d35a1; // seconds between 1.1.1970 and 1.1.2000
|
||||
__int64 ltime = Common::Timer::GetTimeSinceJan1970();
|
||||
return ((u32)ltime - cJanuary2000 - Bias);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user