Initial megacommit.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard
2008-07-12 17:40:22 +00:00
parent a3be5d89ae
commit 775dc8a9c0
1920 changed files with 734652 additions and 0 deletions

View 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>

View 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)");
}
}

View 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

View 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);
}*/

View 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

View 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
}

View 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

View 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();
}

View 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

View 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);
}

View 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

View 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 = &sections[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;
}
*/

View 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

View 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

View 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

View 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

View 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

View 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();
}

View 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

View 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
}

View 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

View 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
}

View 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

View 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

View 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

View 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

View 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

View 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)

View 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);*/
}

View 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

View 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);
}

View 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

View 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(&section, spincount);
}
else
{
InitializeCriticalSection(&section);
}
}
CriticalSection::~CriticalSection()
{
// No need to do anything
}
void CriticalSection::Enter()
{
EnterCriticalSection(&section);
}
bool CriticalSection::TryEnter()
{
return(TryEnterCriticalSection(&section) ? true : false);
}
void CriticalSection::Leave()
{
LeaveCriticalSection(&section);
}
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

View 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

View 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(&ltime);
return((u64)ltime);
}
} // end of namespace Common

View 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

View 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"

View 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>

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

View 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 &reg);
void POP(int bits, const OpArg &reg);
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

File diff suppressed because it is too large Load Diff

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View File

@ -0,0 +1 @@
#pragma once

View 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 = &sections[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;
}

View 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

View 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

View 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");
}
}

View 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

View 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

View 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

View 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";
}

View 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

View 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

View 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

View 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

View 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
}

View 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

View 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

View 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

View 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;
}

View 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

View 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

View 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

View 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();
}

View 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()
{
}

View 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

View 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;
};

View 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);
}
}

View 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

View 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;
}
}

View 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

View 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++;
}
}
}
}

View 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

View 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

View 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

View 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);
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}
}

View 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

View 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;
}

View 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

View 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++;
}

View 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

View 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